All of lore.kernel.org
 help / color / mirror / Atom feed
* [isci-rnc PATCH v1 00/37] remote node context rework
@ 2012-03-23  0:27 Dan Williams
  2012-03-23  0:27 ` [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions Dan Williams
                   ` (36 more replies)
  0 siblings, 37 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:27 UTC (permalink / raw)
  To: linux-scsi

This series is unfortunately being posted during the merge window but has
been in development since the beginning of February.  Part of the delay
in getting it posted was due to waiting for the libsas error-handling
and hotplug work to stabilize, and waiting for the full test results to
come back showing that this development topic was effective.

With these patches, on top of the libsas changes, our hotplug /
exception handling tests are now passing.  Previously we were seeing
frequent system crashes and sometimes locking up the silicon.  I will
let Jeff describe the technical changes in more detail, but it bears
pointing out that this comes with a modest but welcome cleanup of the
code complexity:

 15 files changed, 1316 insertions(+), 1633 deletions(-)

Also available via:

  git://git.kernel.org/pub/scm/linux/kernel/git/djbw/isci.git isci-rnc-v1

...this topic builds on top of isci-for-3.4-v4.

--
Dan

From: Jeff Skirvin

In the controller, devices as they appear on a SAS domain (or
direct-attached SATA devices) are represented by memory structures known
as "Remote Node Contexts" (RNCs).  These structures are transferred from
main memory to the controller using a set of register commands; these
commands include setting up the context ("posting"), removing the
context ("invalidating"), and commands to control the scheduling of
commands and connections to that remote device ("suspensions" and
"resumptions").  There is a similar path to control RNC scheduling from
the protocol engine, which interprets the results of command and data
transmission and reception.

In general, the controller chooses among non-suspended RNCs to find one
that has work requiring scheduling the transmission of command and data
frames to a target.  Likewise, when a target tries to return data back
to the initiator, the state of the RNC is used by the controller to
determine how to treat the incoming request. As an example, if the RNC
is in the state "TX/RX Suspended", incoming SSP connection requests from
the target will be rejected by the controller hardware.  When an RNC is
"TX Suspended", it will not be selected by the controller hardware to
start outgoing command or data operations (with certain priority-based
exceptions).

As mentioned above, there are two sources for management of the RNC
states: commands from driver software, and the result of transmission
and reception conditions of commands and data signaled by the controller
hardware.  As an example of the latter, if an outgoing SSP command ends
with a OPEN_REJECT(BAD_DESTINATION) status, the RNC state will
transition to the "TX Suspended" state, and this is signaled by the
controller hardware in the status to the completion of the pending
command as well as signaled in a controller hardware event.  Examples of
the former are included in the patch changelogs.

Driver software is required to suspend the RNC in a "TX/RX Suspended"
condition before any outstanding commands can be terminated.  Failure to
guarantee this can lead to a complete hardware hang condition.  Earlier
versions of the driver software did not guarantee that an RNC was
correctly managed before I/O termination, and so operated in an unsafe
way.

Further, the driver performed unnecessary contortions to preserve the
remote device command state and so was more complicated than it needed
to be.  A simplifying driver assumption is that once an I/O has entered
the error handler path without having completed in the target, the
requirement on the driver is that all use of the sas_task must end.
Beyond that, recovery of operation is dependent on libsas and other
components to reset, rediscover and reconfigure the device before normal
operation can restart.  In the driver, this simplifying assumption meant
that the RNC management could be reduced to entry into the suspended
state, terminating the targeted I/O request, and resuming the RNC as
needed for device-specific management such as an SSP Abort Task or LUN
Reset Management request.

---

Jeff Skirvin (37):
      isci: Manage the link layer hang detect timer for RNC suspensions.
      isci: Fixed bug in resumption from RNC Tx/Rx suspend state.
      isci: Handle all suspending TC completions
      isci: Terminate outstanding TCs on TX/RX RNC suspensions.
      isci: Manage device suspensions during TC terminations.
      isci: Remote device must be suspended for NCQ cleanup.
      isci: Remote device stop also suspends the RNC and terminates I/O.
      isci: Escalate to I_T_Nexus_Reset when the device is gone.
      isci: Redesign device suspension, abort, cleanup.
      isci: Add suspension cases for RNC INVALIDATING, POSTING states.
      isci: Device access in the error path does not depend on IDEV_GONE.
      isci: All pending TCs are terminated when the RNC is invalidated.
      isci: Only set IDEV_GONE in the device stop path.
      isci: Remove isci_device reqs_in_process and dev_node from isci_device.
      isci: Distinguish between remote device suspension cases
      isci: Fix the terminated I/O to not call sas_task_abort().
      isci: Save the suspension hint for upcoming suspensions.
      isci: Manage the LLHANG timer enable/disable per-device.
      isci: Make sure all TCs are terminated and cleaned in LUN reset.
      isci: Implement waiting for suspend in the abort path.
      isci: When in the abort path, defeat other resume calls until done.
      isci: Callbacks to libsas occur under scic_lock and are synchronized.
      isci: Manage tag releases differently when aborting tasks.
      isci: Fix RNC suspend call for SCI_RESUMING state.
      isci: Wait for RNC resumption before leaving the abort path.
      isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs.
      isci: Add protocol indicator for TMF requests.
      isci: Added timeouts to RNC suspensions in the abort path.
      isci: Change the phy control and link reset interface for HW reasons.
      isci: Don't wait for an RNC suspend if it's being destroyed.
      isci: Restore the ATAPI device RNC management code.
      isci: Check IDEV_GONE before performing abort path operations.
      isci: Remove obviated host callback list.
      isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock.
      isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition.
      isci: Fixed RNC bug that lost the suspension or resumption during destroy
      isci: End the RNC resumption wait when the RNC is destroyed.

 drivers/scsi/isci/host.c                 |  143 ++---
 drivers/scsi/isci/host.h                 |    8 
 drivers/scsi/isci/init.c                 |    3 
 drivers/scsi/isci/phy.c                  |    2 
 drivers/scsi/isci/port.c                 |   45 +-
 drivers/scsi/isci/port.h                 |    5 
 drivers/scsi/isci/remote_device.c        |  547 ++++++++++++++++-----
 drivers/scsi/isci/remote_device.h        |   62 ++
 drivers/scsi/isci/remote_node_context.c  |  345 ++++++++++---
 drivers/scsi/isci/remote_node_context.h  |   43 +-
 drivers/scsi/isci/request.c              |  696 +++++++++++---------------
 drivers/scsi/isci/request.h              |  116 ----
 drivers/scsi/isci/scu_completion_codes.h |    2 
 drivers/scsi/isci/task.c                 |  800 +++++-------------------------
 drivers/scsi/isci/task.h                 |  132 -----
 15 files changed, 1316 insertions(+), 1633 deletions(-)

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
@ 2012-03-23  0:27 ` Dan Williams
  2012-03-23  0:27 ` [isci-rnc PATCH v1 02/37] isci: Fixed bug in resumption from RNC Tx/Rx suspend state Dan Williams
                   ` (35 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:27 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

For STP devices under certain protocol conditions, an RNC will not
suspend until the current transfer state is broken with a SYNC/ESC
sequence from the SCU.  The SYNC/ESC driven by expiration of the
SCU link layer hang detect timer, which has too small a dynamic
range to support slow SATA devices, so normally it is disabled.

This change enables the timer with the minimum period at the point
when the suspension is requested.

Note that there is potential collateral damage to other open
connections to slow SATA devices on the same port, since there
is no alternative but to enable the LLHANG timer on every phy in
the port for the current suspension request - there is no way to
tell on which phy the RNC in question is currently active.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/port.c                |   26 +++++++++++++++++++++++++-
 drivers/scsi/isci/port.h                |    5 +++++
 drivers/scsi/isci/remote_device.h       |    7 +++++++
 drivers/scsi/isci/remote_node_context.c |   15 ++++++++++++++-
 4 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 6ef4bd9..00666f7 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -1546,6 +1546,29 @@ static void sci_port_failed_state_enter(struct sci_base_state_machine *sm)
 	isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT);
 }
 
+void sci_port_set_hang_detection_timeout(struct isci_port *iport, u32 timeout)
+{
+	int phy_index;
+	u32 phy_mask = iport->active_phy_mask;
+
+	if (timeout)
+		++iport->hang_detect_users;
+	else if (iport->hang_detect_users > 1)
+		--iport->hang_detect_users;
+	else
+		iport->hang_detect_users = 0;
+
+	if (timeout || (iport->hang_detect_users == 0)) {
+		for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) {
+			if ((phy_mask >> phy_index) & 1) {
+				writel(timeout,
+				       &iport->phy_table[phy_index]
+					  ->link_layer_registers
+					  ->link_layer_hang_detection_timeout);
+			}
+		}
+	}
+}
 /* --------------------------------------------------------------------------- */
 
 static const struct sci_base_state sci_port_state_table[] = {
@@ -1594,6 +1617,7 @@ void sci_port_construct(struct isci_port *iport, u8 index,
 
 	iport->started_request_count = 0;
 	iport->assigned_device_count = 0;
+	iport->hang_detect_users = 0;
 
 	iport->reserved_rni = SCU_DUMMY_INDEX;
 	iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG;
@@ -1731,7 +1755,7 @@ void isci_port_formed(struct asd_sas_phy *phy)
 	struct isci_host *ihost = phy->ha->lldd_ha;
 	struct isci_phy *iphy = to_iphy(phy);
 	struct asd_sas_port *port = phy->port;
-	struct isci_port *iport;
+	struct isci_port *iport = NULL;
 	unsigned long flags;
 	int i;
 
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index f8bd1e8..861e8f7 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -111,6 +111,7 @@ struct isci_port {
 	u16 reserved_tag;
 	u32 started_request_count;
 	u32 assigned_device_count;
+	u32 hang_detect_users;
 	u32 not_ready_reason;
 	struct isci_phy *phy_table[SCI_MAX_PHYS];
 	struct isci_host *owning_controller;
@@ -269,6 +270,10 @@ void sci_port_get_attached_sas_address(
 	struct isci_port *iport,
 	struct sci_sas_address *sas_address);
 
+void sci_port_set_hang_detection_timeout(
+	struct isci_port *isci_port,
+	u32 timeout);
+
 void isci_port_formed(struct asd_sas_phy *);
 void isci_port_deformed(struct asd_sas_phy *);
 
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 4a67ff0..4850b58 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -301,6 +301,13 @@ static inline void sci_remote_device_decrement_request_count(struct isci_remote_
 		idev->started_request_count--;
 }
 
+static inline void isci_dev_set_hang_detection_timeout(
+	struct isci_remote_device *idev,
+	u32 timeout)
+{
+	sci_port_set_hang_detection_timeout(idev->owning_port, timeout);
+}
+
 enum sci_status sci_remote_device_frame_handler(
 	struct isci_remote_device *idev,
 	u32 frame_index);
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 8ce5a35..3a55ba6 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -316,6 +316,15 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
 	sci_remote_node_context_continue_state_transitions(rnc);
 }
 
+static void sci_remote_node_context_await_suspend_state_exit(
+	struct sci_base_state_machine *sm)
+{
+	struct sci_remote_node_context *rnc
+		= container_of(sm, typeof(*rnc), sm);
+
+	isci_dev_set_hang_detection_timeout(rnc_to_dev(rnc), 0);
+}
+
 static const struct sci_base_state sci_remote_node_context_state_table[] = {
 	[SCI_RNC_INITIAL] = {
 		.enter_state = sci_remote_node_context_initial_state_enter,
@@ -338,7 +347,9 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
 	[SCI_RNC_TX_RX_SUSPENDED] = {
 		.enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
 	},
-	[SCI_RNC_AWAIT_SUSPENSION] = { },
+	[SCI_RNC_AWAIT_SUSPENSION] = {
+		.exit_state = sci_remote_node_context_await_suspend_state_exit,
+	},
 };
 
 void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
@@ -513,6 +524,8 @@ enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *
 	if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
 		sci_remote_device_post_request(rnc_to_dev(sci_rnc),
 						    SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
+		isci_dev_set_hang_detection_timeout(rnc_to_dev(sci_rnc),
+						    0x00000001);
 	}
 
 	sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 02/37] isci: Fixed bug in resumption from RNC Tx/Rx suspend state.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
  2012-03-23  0:27 ` [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions Dan Williams
@ 2012-03-23  0:27 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 03/37] isci: Handle all suspending TC completions Dan Williams
                   ` (34 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:27 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

The resumption from the Tx/Rx suspended state should work the same
as the Tx suspended state.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_node_context.c |   12 +++++++-----
 1 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 3a55ba6..3e84975 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -557,10 +557,16 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 		sci_rnc->user_callback = cb_fn;
 		sci_rnc->user_cookie   = cb_p;
 		return SCI_SUCCESS;
-	case SCI_RNC_TX_SUSPENDED: {
+	case SCI_RNC_TX_SUSPENDED:
+	case SCI_RNC_TX_RX_SUSPENDED: {
 		struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
 		struct domain_device *dev = idev->domain_dev;
 
+		/* If this is an expander attached SATA device we must
+		 * invalidate and repost the RNC since this is the only way
+		 * to clear the TCi to NCQ tag mapping table for the RNi.
+		 * All other device types we can just resume.
+		 */
 		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
 
 		if (dev_is_sata(dev) && dev->parent)
@@ -569,10 +575,6 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 			sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
 		return SCI_SUCCESS;
 	}
-	case SCI_RNC_TX_RX_SUSPENDED:
-		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
-		sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
-		return SCI_FAILURE_INVALID_STATE;
 	case SCI_RNC_AWAIT_SUSPENSION:
 		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
 		return SCI_SUCCESS;


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 03/37] isci: Handle all suspending TC completions
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
  2012-03-23  0:27 ` [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions Dan Williams
  2012-03-23  0:27 ` [isci-rnc PATCH v1 02/37] isci: Fixed bug in resumption from RNC Tx/Rx suspend state Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 04/37] isci: Terminate outstanding TCs on TX/RX RNC suspensions Dan Williams
                   ` (33 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Add comprehensive decode for all TC completions that generate RNC
suspensions.

Note that this commit also removes unconditional resumptions of ATAPI
devices when in the SCI_STP_DEV_ATAPI_ERROR state, and STP devices
when in the SCI_STP_DEV_IDLE state. This is because the SCI_STP_DEV_IDLE
and SCI_STP_DEV_ATAPI state entry functions manage the RNC resumption.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c        |   86 ++++++++---------
 drivers/scsi/isci/remote_device.h        |    4 -
 drivers/scsi/isci/remote_node_context.c  |   74 ++++++++++-----
 drivers/scsi/isci/remote_node_context.h  |   13 ++-
 drivers/scsi/isci/request.c              |  149 ++++++++++++++++++++++++++++--
 drivers/scsi/isci/request.h              |    1 
 drivers/scsi/isci/scu_completion_codes.h |    2 
 7 files changed, 242 insertions(+), 87 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 71f5090..b1a8000 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -265,20 +265,12 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
 	return SCI_SUCCESS;
 }
 
-enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
-					       u32 suspend_type)
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
 {
-	struct sci_base_state_machine *sm = &idev->sm;
-	enum sci_remote_device_states state = sm->current_state_id;
-
-	if (state != SCI_STP_DEV_CMD) {
-		dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n",
-			 __func__, dev_state_name(state));
-		return SCI_FAILURE_INVALID_STATE;
-	}
-
 	return sci_remote_node_context_suspend(&idev->rnc,
-						    suspend_type, NULL, NULL);
+					       SCI_SOFTWARE_SUSPENSION,
+					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
+					       NULL, NULL);
 }
 
 enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
@@ -412,8 +404,6 @@ static void atapi_remote_device_resume_done(void *_dev)
 enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 						     u32 event_code)
 {
-	struct sci_base_state_machine *sm = &idev->sm;
-	enum sci_remote_device_states state = sm->current_state_id;
 	enum sci_status status;
 
 	switch (scu_get_event_type(event_code)) {
@@ -427,9 +417,11 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 			status = SCI_SUCCESS;
 
 			/* Suspend the associated RNC */
-			sci_remote_node_context_suspend(&idev->rnc,
-							      SCI_SOFTWARE_SUSPENSION,
-							      NULL, NULL);
+			sci_remote_node_context_suspend(
+				&idev->rnc,
+				SCI_SOFTWARE_SUSPENSION,
+				SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
+				NULL, NULL);
 
 			dev_dbg(scirdev_to_dev(idev),
 				"%s: device: %p event code: %x: %s\n",
@@ -455,26 +447,6 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 	if (status != SCI_SUCCESS)
 		return status;
 
-	if (state == SCI_STP_DEV_ATAPI_ERROR) {
-		/* For ATAPI error state resume the RNC right away. */
-		if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
-		    scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) {
-			return sci_remote_node_context_resume(&idev->rnc,
-							      atapi_remote_device_resume_done,
-							      idev);
-		}
-	}
-
-	if (state == SCI_STP_DEV_IDLE) {
-
-		/* We pick up suspension events to handle specifically to this
-		 * state. We resume the RNC right away.
-		 */
-		if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
-		    scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX)
-			status = sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
-	}
-
 	return status;
 }
 
@@ -765,11 +737,11 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
 		 * the correct action when the remote node context is suspended
 		 * and later resumed.
 		 */
-		sci_remote_node_context_suspend(&idev->rnc,
-				SCI_SOFTWARE_SUSPENSION, NULL, NULL);
-		sci_remote_node_context_resume(&idev->rnc,
-				sci_remote_device_continue_request,
-						    idev);
+		sci_remote_node_context_suspend(
+			&idev->rnc, SCI_SOFTWARE_SUSPENSION,
+			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
+		sci_remote_node_context_resume(
+			&idev->rnc, sci_remote_device_continue_request, idev);
 
 	out:
 		sci_remote_device_start_request(idev, ireq, status);
@@ -954,14 +926,23 @@ static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm
 static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm)
 {
 	struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+	struct isci_host *ihost = idev->owning_port->owning_controller;
+
+	dev_dbg(&ihost->pdev->dev,
+		"%s: isci_device = %p\n", __func__, idev);
 
 	sci_remote_node_context_suspend(
-		&idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL);
+		&idev->rnc, SCI_SOFTWARE_SUSPENSION,
+		SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
 }
 
 static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm)
 {
 	struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+	struct isci_host *ihost = idev->owning_port->owning_controller;
+
+	dev_dbg(&ihost->pdev->dev,
+		"%s: isci_device = %p\n", __func__, idev);
 
 	sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
 }
@@ -1004,6 +985,21 @@ static void sci_stp_remote_device_ready_ncq_error_substate_enter(struct sci_base
 					     idev->not_ready_reason);
 }
 
+static void sci_stp_remote_device_atapi_error_substate_enter(
+	struct sci_base_state_machine *sm)
+{
+	struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
+
+	/* This state is entered when an I/O is decoded with an error
+	 * condition.  By this point the RNC expected suspension state is set.
+	 * The error conditions suspend the device, so unsuspend here if
+	 * possible.
+	 */
+	sci_remote_node_context_resume(&idev->rnc,
+				       atapi_remote_device_resume_done,
+				       idev);
+}
+
 static void sci_smp_remote_device_ready_idle_substate_enter(struct sci_base_state_machine *sm)
 {
 	struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
@@ -1054,7 +1050,9 @@ static const struct sci_base_state sci_remote_device_state_table[] = {
 	[SCI_STP_DEV_NCQ_ERROR] = {
 		.enter_state = sci_stp_remote_device_ready_ncq_error_substate_enter,
 	},
-	[SCI_STP_DEV_ATAPI_ERROR] = { },
+	[SCI_STP_DEV_ATAPI_ERROR] = {
+		.enter_state = sci_stp_remote_device_atapi_error_substate_enter,
+	},
 	[SCI_STP_DEV_AWAIT_RESET] = { },
 	[SCI_SMP_DEV_IDLE] = {
 		.enter_state = sci_smp_remote_device_ready_idle_substate_enter,
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 4850b58..3915905 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -331,10 +331,6 @@ enum sci_status sci_remote_device_complete_io(
 	struct isci_remote_device *idev,
 	struct isci_request *ireq);
 
-enum sci_status sci_remote_device_suspend(
-	struct isci_remote_device *idev,
-	u32 suspend_type);
-
 void sci_remote_device_post_request(
 	struct isci_remote_device *idev,
 	u32 request);
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 3e84975..f180c72 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -367,6 +367,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 							   u32 event_code)
 {
 	enum scis_sds_remote_node_context_states state;
+	u32 next_state;
 
 	state = sci_rnc->sm.current_state_id;
 	switch (state) {
@@ -425,11 +426,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 		switch (scu_get_event_type(event_code)) {
 		case SCU_EVENT_TL_RNC_SUSPEND_TX:
 			sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
-			sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+			sci_rnc->suspend_type = scu_get_event_type(event_code);
 			break;
 		case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
 			sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
-			sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+			sci_rnc->suspend_type = scu_get_event_type(event_code);
 			break;
 		default:
 			goto out;
@@ -438,16 +439,16 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 	case SCI_RNC_AWAIT_SUSPENSION:
 		switch (scu_get_event_type(event_code)) {
 		case SCU_EVENT_TL_RNC_SUSPEND_TX:
-			sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED);
-			sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+			next_state = SCI_RNC_TX_SUSPENDED;
 			break;
 		case SCU_EVENT_TL_RNC_SUSPEND_TX_RX:
-			sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED);
-			sci_rnc->suspension_code = scu_get_event_specifier(event_code);
+			next_state = SCI_RNC_TX_RX_SUSPENDED;
 			break;
 		default:
 			goto out;
 		}
+		if (sci_rnc->suspend_type == scu_get_event_type(event_code))
+			sci_change_state(&sci_rnc->sm, next_state);
 		break;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
@@ -502,33 +503,60 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 	}
 }
 
-enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
-						     u32 suspend_type,
-						     scics_sds_remote_node_context_callback cb_fn,
-						     void *cb_p)
+enum sci_status sci_remote_node_context_suspend(
+			struct sci_remote_node_context *sci_rnc,
+			enum sci_remote_node_suspension_reasons suspend_reason,
+			u32 suspend_type,
+			scics_sds_remote_node_context_callback cb_fn,
+			void *cb_p)
 {
-	enum scis_sds_remote_node_context_states state;
+	enum scis_sds_remote_node_context_states state
+		= sci_rnc->sm.current_state_id;
+	struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
+	enum sci_status status = SCI_FAILURE_INVALID_STATE;
 
-	state = sci_rnc->sm.current_state_id;
-	if (state != SCI_RNC_READY) {
+	/* Disable automatic state continuations if explicitly suspending. */
+	if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
+		sci_rnc->destination_state
+			= SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+	switch (state) {
+	case SCI_RNC_READY:
+		break;
+	case SCI_RNC_TX_SUSPENDED:
+		if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX)
+			status = SCI_SUCCESS;
+		break;
+	case SCI_RNC_TX_RX_SUSPENDED:
+		if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
+			status = SCI_SUCCESS;
+		break;
+	case SCI_RNC_AWAIT_SUSPENSION:
+		if ((sci_rnc->suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX_RX)
+		    || (suspend_type == sci_rnc->suspend_type))
+			return SCI_SUCCESS;
+		break;
+	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
 			 "%s: invalid state %s\n", __func__,
 			 rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
+	sci_rnc->user_callback = cb_fn;
+	sci_rnc->user_cookie   = cb_p;
+	sci_rnc->suspend_type  = suspend_type;
 
-	sci_rnc->user_callback   = cb_fn;
-	sci_rnc->user_cookie     = cb_p;
-	sci_rnc->suspension_code = suspend_type;
-
-	if (suspend_type == SCI_SOFTWARE_SUSPENSION) {
-		sci_remote_device_post_request(rnc_to_dev(sci_rnc),
-						    SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX);
-		isci_dev_set_hang_detection_timeout(rnc_to_dev(sci_rnc),
-						    0x00000001);
+	if (status == SCI_SUCCESS) { /* Already in the destination state? */
+		sci_remote_node_context_notify_user(sci_rnc);
+		return SCI_SUCCESS;
+	}
+	if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
+		isci_dev_set_hang_detection_timeout(idev, 0x00000001);
+		sci_remote_device_post_request(
+			idev, SCI_SOFTWARE_SUSPEND_CMD);
 	}
+	if (state != SCI_RNC_AWAIT_SUSPENSION)
+		sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
 
-	sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION);
 	return SCI_SUCCESS;
 }
 
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index a241e0f..276fc49 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -75,8 +75,12 @@
  */
 #define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX    0x0FFF
 
-#define SCU_HARDWARE_SUSPENSION  (0)
-#define SCI_SOFTWARE_SUSPENSION  (1)
+enum sci_remote_node_suspension_reasons {
+	SCU_HARDWARE_SUSPENSION,
+	SCI_SOFTWARE_SUSPENSION
+};
+#define SCI_SOFTWARE_SUSPEND_CMD SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX
+#define SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT SCU_EVENT_TL_RNC_SUSPEND_TX_RX
 
 struct isci_request;
 struct isci_remote_device;
@@ -156,10 +160,10 @@ struct sci_remote_node_context {
 	u16 remote_node_index;
 
 	/**
-	 * This field is the recored suspension code or the reason for the remote node
+	 * This field is the recored suspension type of the remote node
 	 * context suspension.
 	 */
-	u32 suspension_code;
+	u32 suspend_type;
 
 	/**
 	 * This field is true if the remote node context is resuming from its current
@@ -200,6 +204,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 						      void *callback_parameter);
 enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
 						     u32 suspend_type,
+						     u32 suspension_code,
 						     scics_sds_remote_node_context_callback cb_fn,
 						     void *cb_p);
 enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 3384ead..847d971 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2116,9 +2116,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
 		 * completion.
 		 */
 		if (ireq->stp.rsp.fis_type == FIS_REGD2H) {
-			sci_remote_device_suspend(ireq->target_device,
-				SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code)));
-
 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
@@ -2138,13 +2135,6 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
 	/* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR
 	 * - this comes only for B0
 	 */
-	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN):
-	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR):
-	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR):
-	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR):
-		sci_remote_device_suspend(ireq->target_device,
-			SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code)));
-		/* Fall through to the default case */
 	default:
 		/* All other completion status cause the IO to be complete. */
 		ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code);
@@ -2262,15 +2252,152 @@ static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ire
 	return status;
 }
 
+static int sci_request_smp_completion_status_is_tx_suspend(
+	unsigned int completion_status)
+{
+	switch (completion_status) {
+	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+		return 1;
+	}
+	return 0;
+}
+
+static int sci_request_smp_completion_status_is_tx_rx_suspend(
+	unsigned int completion_status)
+{
+	return 0; /* There are no Tx/Rx SMP suspend conditions. */
+}
+
+static int sci_request_ssp_completion_status_is_tx_suspend(
+	unsigned int completion_status)
+{
+	switch (completion_status) {
+	case SCU_TASK_DONE_TX_RAW_CMD_ERR:
+	case SCU_TASK_DONE_LF_ERR:
+	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+	case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+	case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+	case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+		return 1;
+	}
+	return 0;
+}
+
+static int sci_request_ssp_completion_status_is_tx_rx_suspend(
+	unsigned int completion_status)
+{
+	return 0; /* There are no Tx/Rx SSP suspend conditions. */
+}
+
+static int sci_request_stpsata_completion_status_is_tx_suspend(
+	unsigned int completion_status)
+{
+	switch (completion_status) {
+	case SCU_TASK_DONE_TX_RAW_CMD_ERR:
+	case SCU_TASK_DONE_LL_R_ERR:
+	case SCU_TASK_DONE_LL_PERR:
+	case SCU_TASK_DONE_REG_ERR:
+	case SCU_TASK_DONE_SDB_ERR:
+	case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
+	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
+	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
+	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
+	case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
+	case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
+	case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
+		return 1;
+	}
+	return 0;
+}
+
+
+static int sci_request_stpsata_completion_status_is_tx_rx_suspend(
+	unsigned int completion_status)
+{
+	switch (completion_status) {
+	case SCU_TASK_DONE_LF_ERR:
+	case SCU_TASK_DONE_LL_SY_TERM:
+	case SCU_TASK_DONE_LL_LF_TERM:
+	case SCU_TASK_DONE_BREAK_RCVD:
+	case SCU_TASK_DONE_INV_FIS_LEN:
+	case SCU_TASK_DONE_UNEXP_FIS:
+	case SCU_TASK_DONE_UNEXP_SDBFIS:
+	case SCU_TASK_DONE_MAX_PLD_ERR:
+		return 1;
+	}
+	return 0;
+}
+
+static void sci_request_handle_suspending_completions(
+	struct isci_request *ireq,
+	u32 completion_code)
+{
+	int is_tx = 0;
+	int is_tx_rx = 0;
+
+	switch (ireq->protocol) {
+	case SAS_PROTOCOL_SMP:
+		is_tx = sci_request_smp_completion_status_is_tx_suspend(
+			completion_code);
+		is_tx_rx = sci_request_smp_completion_status_is_tx_rx_suspend(
+			completion_code);
+		break;
+	case SAS_PROTOCOL_SSP:
+		is_tx = sci_request_ssp_completion_status_is_tx_suspend(
+			completion_code);
+		is_tx_rx = sci_request_ssp_completion_status_is_tx_rx_suspend(
+			completion_code);
+		break;
+	case SAS_PROTOCOL_STP:
+		is_tx = sci_request_stpsata_completion_status_is_tx_suspend(
+			completion_code);
+		is_tx_rx =
+			sci_request_stpsata_completion_status_is_tx_rx_suspend(
+				completion_code);
+		break;
+	default:
+		dev_warn(&ireq->isci_host->pdev->dev,
+			 "%s: request %p has no valid protocol\n",
+			 __func__, ireq);
+		break;
+	}
+	if (is_tx || is_tx_rx) {
+		BUG_ON(is_tx && is_tx_rx);
+
+		sci_remote_node_context_suspend(
+			&ireq->target_device->rnc,
+			SCU_HARDWARE_SUSPENSION,
+			(is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX
+				   : SCU_EVENT_TL_RNC_SUSPEND_TX,
+			NULL, NULL);
+	}
+}
+
 enum sci_status
 sci_io_request_tc_completion(struct isci_request *ireq,
-				  u32 completion_code)
+			     u32 completion_code)
 {
 	enum sci_base_request_states state;
 	struct isci_host *ihost = ireq->owning_controller;
 
 	state = ireq->sm.current_state_id;
 
+	/* Decode those completions that signal upcoming suspension events. */
+	sci_request_handle_suspending_completions(
+		ireq, SCU_GET_COMPLETION_TL_STATUS(completion_code));
+
 	switch (state) {
 	case SCI_REQ_STARTED:
 		return request_started_state_tc_event(ireq, completion_code);
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 4961f9f..e845a31 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -414,5 +414,4 @@ static inline int isci_task_is_ncq_recovery(struct sas_task *task)
 		task->ata_task.fis.lbal == ATA_LOG_SATA_NCQ);
 
 }
-
 #endif /* !defined(_ISCI_REQUEST_H_) */
diff --git a/drivers/scsi/isci/scu_completion_codes.h b/drivers/scsi/isci/scu_completion_codes.h
index c8b329c..071cb74 100644
--- a/drivers/scsi/isci/scu_completion_codes.h
+++ b/drivers/scsi/isci/scu_completion_codes.h
@@ -224,6 +224,7 @@
  * 32-bit value like we want, each immediate value must be cast to a u32.
  */
 #define SCU_TASK_DONE_GOOD                                  ((u32)0x00)
+#define SCU_TASK_DONE_TX_RAW_CMD_ERR                        ((u32)0x08)
 #define SCU_TASK_DONE_CRC_ERR                               ((u32)0x14)
 #define SCU_TASK_DONE_CHECK_RESPONSE                        ((u32)0x14)
 #define SCU_TASK_DONE_GEN_RESPONSE                          ((u32)0x15)
@@ -237,6 +238,7 @@
 #define SCU_TASK_DONE_LL_LF_TERM                            ((u32)0x1A)
 #define SCU_TASK_DONE_DATA_LEN_ERR                          ((u32)0x1A)
 #define SCU_TASK_DONE_LL_CL_TERM                            ((u32)0x1B)
+#define SCU_TASK_DONE_BREAK_RCVD                            ((u32)0x1B)
 #define SCU_TASK_DONE_LL_ABORT_ERR                          ((u32)0x1B)
 #define SCU_TASK_DONE_SEQ_INV_TYPE                          ((u32)0x1C)
 #define SCU_TASK_DONE_UNEXP_XR                              ((u32)0x1C)


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 04/37] isci: Terminate outstanding TCs on TX/RX RNC suspensions.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (2 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 03/37] isci: Handle all suspending TC completions Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 05/37] isci: Manage device suspensions during TC terminations Dan Williams
                   ` (32 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

TCs must only be terminated when RNCs are suspended.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c                |   22 +++---
 drivers/scsi/isci/remote_device.c       |  106 ++++++++++++++++++++++++++++---
 drivers/scsi/isci/remote_device.h       |   10 +++
 drivers/scsi/isci/remote_node_context.c |   56 ++++++++++++++++
 drivers/scsi/isci/remote_node_context.h |    2 +
 drivers/scsi/isci/request.c             |   22 ++++--
 drivers/scsi/isci/request.h             |    2 +
 7 files changed, 188 insertions(+), 32 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 95c3da6..a43bc22 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -2678,18 +2678,18 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
 			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
-
 	status = sci_io_request_terminate(ireq);
-	if (status != SCI_SUCCESS)
-		return status;
-
-	/*
-	 * Utilize the original post context command and or in the POST_TC_ABORT
-	 * request sub-type.
-	 */
-	sci_controller_post_request(ihost,
-				    ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
-	return SCI_SUCCESS;
+	if ((status == SCI_SUCCESS) &&
+	    !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
+	    !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
+		/* Utilize the original post context command and or in the
+		 * POST_TC_ABORT request sub-type.
+		 */
+		sci_controller_post_request(
+			ihost, ireq->post_context |
+				SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT);
+	}
+	return status;
 }
 
 /**
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index b1a8000..9f03877 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -133,6 +133,50 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
 		wake_up(&ihost->eventq);
 }
 
+static enum sci_status sci_remote_device_suspend(
+	struct isci_remote_device *idev)
+{
+	return sci_remote_node_context_suspend(
+		&idev->rnc,
+		SCI_SOFTWARE_SUSPENSION,
+		SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
+		NULL, NULL);
+}
+
+enum sci_status isci_remote_device_suspend(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev)
+{
+	enum sci_status status;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+
+	if (isci_lookup_device(idev->domain_dev) == NULL) {
+		spin_unlock_irqrestore(&ihost->scic_lock, flags);
+		status = SCI_FAILURE;
+	} else {
+		status = sci_remote_device_suspend(idev);
+		spin_unlock_irqrestore(&ihost->scic_lock, flags);
+		if (status == SCI_SUCCESS) {
+			wait_event(ihost->eventq,
+				   test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
+				|| !test_bit(IDEV_ALLOCATED, &idev->flags));
+
+			status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
+					? SCI_SUCCESS : SCI_FAILURE;
+			dev_dbg(&ihost->pdev->dev,
+				"%s: idev=%p, wait done, device is %s\n",
+				__func__, idev,
+				test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
+					? "<suspended>" : "<deallocated!>");
+
+		}
+		isci_put_device(idev);
+	}
+	return status;
+}
+
 /* called once the remote node context is ready to be freed.
  * The remote device can now report that its stop operation is complete. none
  */
@@ -144,7 +188,9 @@ static void rnc_destruct_done(void *_dev)
 	sci_change_state(&idev->sm, SCI_DEV_STOPPED);
 }
 
-static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev)
+static enum sci_status sci_remote_device_terminate_requests_checkabort(
+	struct isci_remote_device *idev,
+	int check_abort_pending)
 {
 	struct isci_host *ihost = idev->owning_port->owning_controller;
 	enum sci_status status  = SCI_SUCCESS;
@@ -155,7 +201,9 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
 		enum sci_status s;
 
 		if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
-		    ireq->target_device != idev)
+		    (ireq->target_device != idev) ||
+		    (check_abort_pending && !test_bit(IREQ_PENDING_ABORT,
+						      &ireq->flags)))
 			continue;
 
 		s = sci_controller_terminate_request(ihost, idev, ireq);
@@ -166,6 +214,12 @@ static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_d
 	return status;
 }
 
+enum sci_status sci_remote_device_terminate_requests(
+	struct isci_remote_device *idev)
+{
+	return sci_remote_device_terminate_requests_checkabort(idev, 0);
+}
+
 enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
 					u32 timeout)
 {
@@ -265,14 +319,6 @@ enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev
 	return SCI_SUCCESS;
 }
 
-enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
-{
-	return sci_remote_node_context_suspend(&idev->rnc,
-					       SCI_SOFTWARE_SUSPENSION,
-					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
-					       NULL, NULL);
-}
-
 enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev,
 						     u32 frame_index)
 {
@@ -1186,7 +1232,7 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
  * the device when there have been no phys added to it.
  */
 static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
-						u32 timeout)
+					       u32 timeout)
 {
 	struct sci_base_state_machine *sm = &idev->sm;
 	enum sci_remote_device_states state = sm->current_state_id;
@@ -1413,3 +1459,41 @@ int isci_remote_device_found(struct domain_device *dev)
 
 	return status == SCI_SUCCESS ? 0 : -ENODEV;
 }
+
+enum sci_status isci_remote_device_reset(
+	struct isci_remote_device *idev)
+{
+	struct isci_host *ihost = dev_to_ihost(idev->domain_dev);
+	unsigned long flags;
+	enum sci_status status;
+
+	/* Wait for the device suspend. */
+	status = isci_remote_device_suspend(ihost, idev);
+	if (status != SCI_SUCCESS) {
+		dev_dbg(&ihost->pdev->dev,
+			"%s: isci_remote_device_suspend(%p) returned %d!\n",
+			__func__, idev, status);
+		return status;
+	}
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	status = sci_remote_device_reset(idev);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+	if (status != SCI_SUCCESS) {
+		dev_dbg(&ihost->pdev->dev,
+			"%s: sci_remote_device_reset(%p) returned %d!\n",
+			__func__, idev, status);
+	}
+	return status;
+}
+
+int isci_remote_device_is_safe_to_abort(
+	struct isci_remote_device *idev)
+{
+	return sci_remote_node_context_is_safe_to_abort(&idev->rnc);
+}
+
+enum sci_status sci_remote_device_abort_requests_pending_abort(
+	struct isci_remote_device *idev)
+{
+	return sci_remote_device_terminate_requests_checkabort(idev, 1);
+}
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 3915905..ae508ee 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -85,6 +85,7 @@ struct isci_remote_device {
 	#define IDEV_GONE 3
 	#define IDEV_IO_READY 4
 	#define IDEV_IO_NCQERROR 5
+	#define IDEV_TXRX_SUSPENDED 6
 	unsigned long flags;
 	struct kref kref;
 	struct isci_port *isci_port;
@@ -335,4 +336,13 @@ void sci_remote_device_post_request(
 	struct isci_remote_device *idev,
 	u32 request);
 
+enum sci_status sci_remote_device_terminate_requests(
+	struct isci_remote_device *idev);
+
+int isci_remote_device_is_safe_to_abort(
+	struct isci_remote_device *idev);
+
+enum sci_status
+sci_remote_device_abort_requests_pending_abort(
+	struct isci_remote_device *idev);
 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index f180c72..7a8347e 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -268,6 +268,8 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta
 {
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
 
+	/* Terminate outstanding requests pending abort. */
+	sci_remote_device_abort_requests_pending_abort(rnc_to_dev(rnc));
 	sci_remote_node_context_invalidate_context_buffer(rnc);
 }
 
@@ -312,10 +314,28 @@ static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_sta
 static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm)
 {
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
+	struct isci_remote_device *idev = rnc_to_dev(rnc);
+	struct isci_host *ihost = idev->owning_port->owning_controller;
+
+	set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
 
+	/* Terminate outstanding requests pending abort. */
+	sci_remote_device_abort_requests_pending_abort(idev);
+
+	wake_up(&ihost->eventq);
 	sci_remote_node_context_continue_state_transitions(rnc);
 }
 
+static void sci_remote_node_context_tx_rx_suspended_state_exit(
+	struct sci_base_state_machine *sm)
+{
+	struct sci_remote_node_context *rnc
+		= container_of(sm, typeof(*rnc), sm);
+	struct isci_remote_device *idev = rnc_to_dev(rnc);
+
+	clear_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
+}
+
 static void sci_remote_node_context_await_suspend_state_exit(
 	struct sci_base_state_machine *sm)
 {
@@ -346,6 +366,8 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
 	},
 	[SCI_RNC_TX_RX_SUSPENDED] = {
 		.enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
+		.exit_state
+			= sci_remote_node_context_tx_rx_suspended_state_exit,
 	},
 	[SCI_RNC_AWAIT_SUSPENSION] = {
 		.exit_state = sci_remote_node_context_await_suspend_state_exit,
@@ -515,6 +537,13 @@ enum sci_status sci_remote_node_context_suspend(
 	struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
 	enum sci_status status = SCI_FAILURE_INVALID_STATE;
 
+	dev_dbg(scirdev_to_dev(idev),
+		"%s: current state %d, current suspend_type %x dest state %d,"
+			" arg suspend_reason %d, arg suspend_type %x",
+		__func__, state, sci_rnc->suspend_type,
+		sci_rnc->destination_state, suspend_reason,
+		suspend_type);
+
 	/* Disable automatic state continuations if explicitly suspending. */
 	if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
 		sci_rnc->destination_state
@@ -546,7 +575,10 @@ enum sci_status sci_remote_node_context_suspend(
 	sci_rnc->suspend_type  = suspend_type;
 
 	if (status == SCI_SUCCESS) { /* Already in the destination state? */
+		struct isci_host *ihost = idev->owning_port->owning_controller;
+
 		sci_remote_node_context_notify_user(sci_rnc);
+		wake_up_all(&ihost->eventq); /* Let observers look. */
 		return SCI_SUCCESS;
 	}
 	if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
@@ -661,3 +693,27 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
+
+int sci_remote_node_context_is_safe_to_abort(
+	struct sci_remote_node_context *sci_rnc)
+{
+	enum scis_sds_remote_node_context_states state;
+
+	state = sci_rnc->sm.current_state_id;
+	switch (state) {
+	case SCI_RNC_INVALIDATING:
+	case SCI_RNC_TX_RX_SUSPENDED:
+		return 1;
+	case SCI_RNC_POSTING:
+	case SCI_RNC_RESUMING:
+	case SCI_RNC_READY:
+	case SCI_RNC_TX_SUSPENDED:
+	case SCI_RNC_AWAIT_SUSPENSION:
+	case SCI_RNC_INITIAL:
+		return 0;
+	default:
+		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+			 "%s: invalid state %d\n", __func__, state);
+		return 0;
+	}
+}
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 276fc49..5ddf88b 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -214,5 +214,7 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
 							struct isci_request *ireq);
 enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
 						      struct isci_request *ireq);
+int sci_remote_node_context_is_safe_to_abort(
+	struct sci_remote_node_context *sci_rnc);
 
 #endif  /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 847d971..d0386e1 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -863,6 +863,8 @@ sci_io_request_terminate(struct isci_request *ireq)
 
 	switch (state) {
 	case SCI_REQ_CONSTRUCTED:
+		/* Set to make sure no HW terminate posting is done: */
+		set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags);
 		ireq->scu_status = SCU_TASK_DONE_TASK_ABORT;
 		ireq->sci_status = SCI_FAILURE_IO_TERMINATED;
 		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
@@ -883,8 +885,7 @@ sci_io_request_terminate(struct isci_request *ireq)
 	case SCI_REQ_ATAPI_WAIT_PIO_SETUP:
 	case SCI_REQ_ATAPI_WAIT_D2H:
 	case SCI_REQ_ATAPI_WAIT_TC_COMP:
-		sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
-		return SCI_SUCCESS;
+		/* Fall through and change state to ABORTING... */
 	case SCI_REQ_TASK_WAIT_TC_RESP:
 		/* The task frame was already confirmed to have been
 		 * sent by the SCU HW.  Since the state machine is
@@ -893,20 +894,21 @@ sci_io_request_terminate(struct isci_request *ireq)
 		 * and don't wait for the task response.
 		 */
 		sci_change_state(&ireq->sm, SCI_REQ_ABORTING);
-		sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);
-		return SCI_SUCCESS;
+		/* Fall through and handle like ABORTING... */
 	case SCI_REQ_ABORTING:
-		/* If a request has a termination requested twice, return
-		 * a failure indication, since HW confirmation of the first
-		 * abort is still outstanding.
+		if (!isci_remote_device_is_safe_to_abort(ireq->target_device))
+			set_bit(IREQ_PENDING_ABORT, &ireq->flags);
+		else
+			clear_bit(IREQ_PENDING_ABORT, &ireq->flags);
+		/* If the request is only waiting on the remote device
+		 * suspension, return SUCCESS so the caller will wait too.
 		 */
+		return SCI_SUCCESS;
 	case SCI_REQ_COMPLETED:
 	default:
 		dev_warn(&ireq->owning_controller->pdev->dev,
 			 "%s: SCIC IO Request requested to abort while in wrong "
-			 "state %d\n",
-			 __func__,
-			 ireq->sm.current_state_id);
+			 "state %d\n", __func__, ireq->sm.current_state_id);
 		break;
 	}
 
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index e845a31..8d55f78 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -102,6 +102,8 @@ struct isci_request {
 	#define IREQ_TERMINATED 1
 	#define IREQ_TMF 2
 	#define IREQ_ACTIVE 3
+	#define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
+	#define IREQ_TC_ABORT_POSTED 5
 	unsigned long flags;
 	/* XXX kill ttype and ttype_ptr, allocate full sas_task */
 	union ttype_ptr_union {


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 05/37] isci: Manage device suspensions during TC terminations.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (3 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 04/37] isci: Terminate outstanding TCs on TX/RX RNC suspensions Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 06/37] isci: Remote device must be suspended for NCQ cleanup Dan Williams
                   ` (31 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

TCs must be terminated only while the RNC is suspended.  This commit
adds remote device suspensions and resumptions in the abort, reset and
termination paths.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c |   90 ++++++++++++++++++++++++++++++-------
 drivers/scsi/isci/remote_device.h |   33 ++++++++++++++
 drivers/scsi/isci/task.c          |   80 ++++++++++++++++++++-------------
 3 files changed, 154 insertions(+), 49 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 9f03877..4f76dcd 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -143,6 +143,12 @@ static enum sci_status sci_remote_device_suspend(
 		NULL, NULL);
 }
 
+static int isci_remote_device_suspendcheck(struct isci_remote_device *idev)
+{
+	return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
+	    || !test_bit(IDEV_ALLOCATED, &idev->flags);
+}
+
 enum sci_status isci_remote_device_suspend(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev)
@@ -151,18 +157,18 @@ enum sci_status isci_remote_device_suspend(
 	unsigned long flags;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-
-	if (isci_lookup_device(idev->domain_dev) == NULL) {
+	if (isci_get_device(idev->domain_dev) == NULL) {
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		status = SCI_FAILURE;
 	} else {
 		status = sci_remote_device_suspend(idev);
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		if (status == SCI_SUCCESS) {
+			dev_dbg(&ihost->pdev->dev,
+				"%s: idev=%p, about to wait\n",
+				__func__, idev);
 			wait_event(ihost->eventq,
-				   test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-				|| !test_bit(IDEV_ALLOCATED, &idev->flags));
-
+				   isci_remote_device_suspendcheck(idev));
 			status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
 					? SCI_SUCCESS : SCI_FAILURE;
 			dev_dbg(&ihost->pdev->dev,
@@ -171,7 +177,10 @@ enum sci_status isci_remote_device_suspend(
 				test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
 					? "<suspended>" : "<deallocated!>");
 
-		}
+		} else
+			dev_dbg(scirdev_to_dev(idev),
+				 "%s: sci_remote_device_suspend failed, "
+				 "status = %d\n", __func__, status);
 		isci_put_device(idev);
 	}
 	return status;
@@ -1218,6 +1227,35 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
 	return SCI_SUCCESS;
 }
 
+enum sci_status sci_remote_device_resume(
+	struct isci_remote_device *idev,
+	scics_sds_remote_node_context_callback cb_fn,
+	void *cb_p)
+{
+	enum sci_status status;
+
+	status = sci_remote_node_context_resume(&idev->rnc, cb_fn, cb_p);
+	if (status != SCI_SUCCESS)
+		dev_dbg(scirdev_to_dev(idev), "%s: failed to resume: %d\n",
+			__func__, status);
+	return status;
+}
+
+enum sci_status isci_remote_device_resume(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	scics_sds_remote_node_context_callback cb_fn,
+	void *cb_p)
+{
+	unsigned long flags;
+	enum sci_status status;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	status = sci_remote_device_resume(idev, cb_fn, cb_p);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	return status;
+}
 /**
  * sci_remote_device_start() - This method will start the supplied remote
  *    device.  This method enables normal IO requests to flow through to the
@@ -1244,9 +1282,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
-	status = sci_remote_node_context_resume(&idev->rnc,
-						     remote_device_resume_done,
-						     idev);
+	status = sci_remote_device_resume(idev, remote_device_resume_done,
+					  idev);
 	if (status != SCI_SUCCESS)
 		return status;
 
@@ -1461,26 +1498,29 @@ int isci_remote_device_found(struct domain_device *dev)
 }
 
 enum sci_status isci_remote_device_reset(
+	struct isci_host *ihost,
 	struct isci_remote_device *idev)
 {
-	struct isci_host *ihost = dev_to_ihost(idev->domain_dev);
 	unsigned long flags;
 	enum sci_status status;
 
-	/* Wait for the device suspend. */
-	status = isci_remote_device_suspend(ihost, idev);
+	/* Put the device into a reset state so the suspension will not
+	 * automatically resume.
+	 */
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	status = sci_remote_device_reset(idev);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 	if (status != SCI_SUCCESS) {
 		dev_dbg(&ihost->pdev->dev,
-			"%s: isci_remote_device_suspend(%p) returned %d!\n",
+			"%s: sci_remote_device_reset(%p) returned %d!\n",
 			__func__, idev, status);
 		return status;
 	}
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-	status = sci_remote_device_reset(idev);
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+	/* Wait for the device suspend. */
+	status = isci_remote_device_suspend(ihost, idev);
 	if (status != SCI_SUCCESS) {
 		dev_dbg(&ihost->pdev->dev,
-			"%s: sci_remote_device_reset(%p) returned %d!\n",
+			"%s: isci_remote_device_suspend(%p) returned %d!\n",
 			__func__, idev, status);
 	}
 	return status;
@@ -1497,3 +1537,19 @@ enum sci_status sci_remote_device_abort_requests_pending_abort(
 {
 	return sci_remote_device_terminate_requests_checkabort(idev, 1);
 }
+
+enum sci_status isci_remote_device_reset_complete(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev)
+{
+	unsigned long flags;
+	enum sci_status status;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	status = sci_remote_device_reset_complete(idev);
+	sci_remote_device_resume(idev, NULL, NULL);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	return status;
+}
+
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index ae508ee..a6a376e 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -106,6 +106,16 @@ struct isci_remote_device {
 #define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000
 
 /* device reference routines must be called under sci_lock */
+static inline struct isci_remote_device *isci_get_device(
+	struct domain_device *dev)
+{
+	struct isci_remote_device *idev = dev->lldd_dev;
+
+	if (idev)
+		kref_get(&idev->kref);
+	return idev;
+}
+
 static inline struct isci_remote_device *isci_lookup_device(struct domain_device *dev)
 {
 	struct isci_remote_device *idev = dev->lldd_dev;
@@ -345,4 +355,27 @@ int isci_remote_device_is_safe_to_abort(
 enum sci_status
 sci_remote_device_abort_requests_pending_abort(
 	struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_suspend(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev);
+
+enum sci_status sci_remote_device_resume(
+	struct isci_remote_device *idev,
+	scics_sds_remote_node_context_callback cb_fn,
+	void *cb_p);
+
+enum sci_status isci_remote_device_resume(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	scics_sds_remote_node_context_callback cb_fn,
+	void *cb_p);
+
+enum sci_status isci_remote_device_reset(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_reset_complete(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev);
 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 374254e..9b8632f 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -716,6 +716,8 @@ void isci_terminate_pending_requests(struct isci_host *ihost,
 	unsigned long flags;
 	LIST_HEAD(list);
 
+	isci_remote_device_suspend(ihost, idev);
+
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	list_splice_init(&idev->reqs_in_process, &list);
 
@@ -826,40 +828,47 @@ static int isci_task_send_lu_reset_sas(
 
 int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 {
-	struct isci_host *isci_host = dev_to_ihost(dev);
+	struct isci_host *ihost = dev_to_ihost(dev);
 	struct isci_remote_device *isci_device;
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&isci_host->scic_lock, flags);
+	spin_lock_irqsave(&ihost->scic_lock, flags);
 	isci_device = isci_lookup_device(dev);
-	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-	dev_dbg(&isci_host->pdev->dev,
+	dev_dbg(&ihost->pdev->dev,
 		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
-		 __func__, dev, isci_host, isci_device);
+		__func__, dev, ihost, isci_device);
 
 	if (!isci_device) {
 		/* If the device is gone, stop the escalations. */
-		dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__);
+		dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__);
 
 		ret = TMF_RESP_FUNC_COMPLETE;
 		goto out;
 	}
+	if (isci_remote_device_suspend(ihost, isci_device) != SCI_SUCCESS) {
+		dev_dbg(&ihost->pdev->dev,
+			"%s:  device = %p; failed to suspend\n",
+			__func__, isci_device);
+		ret = TMF_RESP_FUNC_FAILED;
+		goto out;
+	}
 
 	/* Send the task management part of the reset. */
 	if (dev_is_sata(dev)) {
 		sas_ata_schedule_reset(dev);
 		ret = TMF_RESP_FUNC_COMPLETE;
 	} else
-		ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
+		ret = isci_task_send_lu_reset_sas(ihost, isci_device, lun);
 
 	/* If the LUN reset worked, all the I/O can now be terminated. */
-	if (ret == TMF_RESP_FUNC_COMPLETE)
+	if (ret == TMF_RESP_FUNC_COMPLETE) {
 		/* Terminate all I/O now. */
-		isci_terminate_pending_requests(isci_host,
-						isci_device);
-
+		isci_terminate_pending_requests(ihost, isci_device);
+		isci_remote_device_resume(ihost, isci_device, NULL, NULL);
+	}
  out:
 	isci_put_device(isci_device);
 	return ret;
@@ -976,7 +985,7 @@ int isci_task_abort_task(struct sas_task *task)
 	spin_unlock(&task->task_state_lock);
 	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
-	dev_dbg(&isci_host->pdev->dev,
+	dev_warn(&isci_host->pdev->dev,
 		"%s: dev = %p, task = %p, old_request == %p\n",
 		__func__, isci_device, task, old_request);
 
@@ -998,7 +1007,7 @@ int isci_task_abort_task(struct sas_task *task)
 
 		ret = TMF_RESP_FUNC_COMPLETE;
 
-		dev_dbg(&isci_host->pdev->dev,
+		dev_warn(&isci_host->pdev->dev,
 			"%s: abort task not needed for %p\n",
 			__func__, task);
 		goto out;
@@ -1022,7 +1031,7 @@ int isci_task_abort_task(struct sas_task *task)
 		/* The request was already being handled by someone else (because
 		* they got to set the state away from started).
 		*/
-		dev_dbg(&isci_host->pdev->dev,
+		dev_warn(&isci_host->pdev->dev,
 			"%s:  device = %p; old_request %p already being aborted\n",
 			__func__,
 			isci_device, old_request);
@@ -1035,7 +1044,7 @@ int isci_task_abort_task(struct sas_task *task)
 
 		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
-		dev_dbg(&isci_host->pdev->dev,
+		dev_warn(&isci_host->pdev->dev,
 			"%s: %s request"
 			" or complete_in_target (%d), thus no TMF\n",
 			__func__,
@@ -1068,6 +1077,15 @@ int isci_task_abort_task(struct sas_task *task)
 		 */
 		perform_termination = 1;
 
+		if (isci_device && !test_bit(IDEV_GONE, &isci_device->flags) &&
+		    (isci_remote_device_suspend(isci_host, isci_device)
+		     != SCI_SUCCESS)) {
+			dev_warn(&isci_host->pdev->dev,
+				"%s:  device = %p; failed to suspend\n",
+				__func__, isci_device);
+			goto out;
+		}
+
 	} else {
 		/* Fill in the tmf stucture */
 		isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
@@ -1076,6 +1094,14 @@ int isci_task_abort_task(struct sas_task *task)
 
 		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
+		if (isci_remote_device_suspend(isci_host, isci_device)
+		    != SCI_SUCCESS) {
+			dev_warn(&isci_host->pdev->dev,
+				"%s:  device = %p; failed to suspend\n",
+				__func__, isci_device);
+			goto out;
+		}
+
 		#define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
 		ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
 					    ISCI_ABORT_TASK_TIMEOUT_MS);
@@ -1083,7 +1109,7 @@ int isci_task_abort_task(struct sas_task *task)
 		if (ret == TMF_RESP_FUNC_COMPLETE)
 			perform_termination = 1;
 		else
-			dev_dbg(&isci_host->pdev->dev,
+			dev_warn(&isci_host->pdev->dev,
 				"%s: isci_task_send_tmf failed\n", __func__);
 	}
 	if (perform_termination) {
@@ -1094,6 +1120,7 @@ int isci_task_abort_task(struct sas_task *task)
 		 */
 		isci_terminate_request_core(isci_host, isci_device,
 					    old_request);
+		isci_remote_device_resume(isci_host, isci_device, NULL, NULL);
 	}
 
 	/* Make sure we do not leave a reference to aborted_io_completion */
@@ -1251,21 +1278,13 @@ static int isci_reset_device(struct isci_host *ihost,
 			     struct isci_remote_device *idev)
 {
 	int rc;
-	unsigned long flags;
 	enum sci_status status;
 	struct sas_phy *phy = sas_get_local_phy(dev);
 	struct isci_port *iport = dev->port->lldd_port;
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
 
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-	status = sci_remote_device_reset(idev);
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-	if (status != SCI_SUCCESS) {
-		dev_dbg(&ihost->pdev->dev,
-			 "%s: sci_remote_device_reset(%p) returned %d!\n",
-			 __func__, idev, status);
+	if (isci_remote_device_reset(ihost, idev) != SCI_SUCCESS) {
 		rc = TMF_RESP_FUNC_FAILED;
 		goto out;
 	}
@@ -1281,15 +1300,12 @@ static int isci_reset_device(struct isci_host *ihost,
 	isci_remote_device_nuke_requests(ihost, idev);
 
 	/* Since all pending TCs have been cleaned, resume the RNC. */
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-	status = sci_remote_device_reset_complete(idev);
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+	status = isci_remote_device_reset_complete(ihost, idev);
 
-	if (status != SCI_SUCCESS) {
+	if (status != SCI_SUCCESS)
 		dev_dbg(&ihost->pdev->dev,
-			 "%s: sci_remote_device_reset_complete(%p) "
+			 "%s: isci_remote_device_reset_complete(%p) "
 			 "returned %d!\n", __func__, idev, status);
-	}
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
  out:
@@ -1305,7 +1321,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
 	int ret;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	idev = isci_lookup_device(dev);
+	idev = isci_get_device(dev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	if (!idev) {


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 06/37] isci: Remote device must be suspended for NCQ cleanup.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (4 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 05/37] isci: Manage device suspensions during TC terminations Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 07/37] isci: Remote device stop also suspends the RNC and terminates I/O Dan Williams
                   ` (30 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

When the remote device enters the NCQ error state, the device must
be suspended so that the I/O terminations can take place.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c |   25 ++++++++++++-------------
 1 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 4f76dcd..f40d429 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -72,6 +72,14 @@ const char *dev_state_name(enum sci_remote_device_states state)
 }
 #undef C
 
+static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
+{
+	return sci_remote_node_context_suspend(&idev->rnc,
+					       SCI_SOFTWARE_SUSPENSION,
+					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
+					       NULL, NULL);
+}
+
 /**
  * isci_remote_device_not_ready() - This function is called by the ihost when
  *    the remote device is not ready. We mark the isci device as ready (not
@@ -96,6 +104,9 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
 	case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
 		set_bit(IDEV_IO_NCQERROR, &idev->flags);
 
+		/* Suspend the remote device so the I/O can be terminated. */
+		sci_remote_device_suspend(idev);
+
 		/* Kill all outstanding requests for the device. */
 		list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) {
 
@@ -103,9 +114,7 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
 				"%s: isci_device = %p request = %p\n",
 				__func__, idev, ireq);
 
-			sci_controller_terminate_request(ihost,
-							  idev,
-							  ireq);
+			sci_controller_terminate_request(ihost, idev, ireq);
 		}
 		/* Fall through into the default case... */
 	default:
@@ -133,16 +142,6 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
 		wake_up(&ihost->eventq);
 }
 
-static enum sci_status sci_remote_device_suspend(
-	struct isci_remote_device *idev)
-{
-	return sci_remote_node_context_suspend(
-		&idev->rnc,
-		SCI_SOFTWARE_SUSPENSION,
-		SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
-		NULL, NULL);
-}
-
 static int isci_remote_device_suspendcheck(struct isci_remote_device *idev)
 {
 	return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 07/37] isci: Remote device stop also suspends the RNC and terminates I/O.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (5 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 06/37] isci: Remote device must be suspended for NCQ cleanup Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 08/37] isci: Escalate to I_T_Nexus_Reset when the device is gone Dan Williams
                   ` (29 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Fixing the remote device state machine to suspend and terminate
all outstanding I/O before the device stopped state is reached.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c |   23 +++++++++++------------
 1 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index f40d429..3048e02 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -263,13 +263,15 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
 	case SCI_SMP_DEV_IDLE:
 	case SCI_SMP_DEV_CMD:
 		sci_change_state(sm, SCI_DEV_STOPPING);
-		if (idev->started_request_count == 0) {
+		if (idev->started_request_count == 0)
 			sci_remote_node_context_destruct(&idev->rnc,
-							      rnc_destruct_done, idev);
-			return SCI_SUCCESS;
-		} else
-			return sci_remote_device_terminate_requests(idev);
-		break;
+							 rnc_destruct_done,
+							 idev);
+		else {
+			sci_remote_device_suspend(idev);
+			sci_remote_device_terminate_requests(idev);
+		}
+		return SCI_SUCCESS;
 	case SCI_DEV_STOPPING:
 		/* All requests should have been terminated, but if there is an
 		 * attempt to stop a device already in the stopping state, then
@@ -1403,14 +1405,8 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	idev->domain_dev->lldd_dev = NULL; /* disable new lookups */
 	set_bit(IDEV_GONE, &idev->flags);
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-	/* Kill all outstanding requests. */
-	isci_remote_device_nuke_requests(ihost, idev);
 
 	set_bit(IDEV_STOP_PENDING, &idev->flags);
-
-	spin_lock_irqsave(&ihost->scic_lock, flags);
 	status = sci_remote_device_stop(idev, 50);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
@@ -1420,6 +1416,9 @@ enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_rem
 	else
 		wait_for_device_stop(ihost, idev);
 
+	dev_dbg(&ihost->pdev->dev,
+		"%s: isci_device = %p, waiting done.\n", __func__, idev);
+
 	return status;
 }
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 08/37] isci: Escalate to I_T_Nexus_Reset when the device is gone.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (6 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 07/37] isci: Remote device stop also suspends the RNC and terminates I/O Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 09/37] isci: Redesign device suspension, abort, cleanup Dan Williams
                   ` (28 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

If LUN reset sees that the device is gone, it returns TMF_RESP_FUNC_FAILED
to cause libsas to escalate to an I_T_Nexus_Reset.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/task.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 9b8632f..26de06e 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -842,10 +842,10 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 		__func__, dev, ihost, isci_device);
 
 	if (!isci_device) {
-		/* If the device is gone, stop the escalations. */
+		/* If the device is gone, escalate to I_T_Nexus_Reset. */
 		dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__);
 
-		ret = TMF_RESP_FUNC_COMPLETE;
+		ret = TMF_RESP_FUNC_FAILED;
 		goto out;
 	}
 	if (isci_remote_device_suspend(ihost, isci_device) != SCI_SUCCESS) {


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 09/37] isci: Redesign device suspension, abort, cleanup.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (7 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 08/37] isci: Escalate to I_T_Nexus_Reset when the device is gone Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 10/37] isci: Add suspension cases for RNC INVALIDATING, POSTING states Dan Williams
                   ` (27 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

This commit changes the means by which outstanding I/Os are handled
for cleanup.
The likelihood is that this commit will be broken into smaller pieces,
however that will be a later revision.  Among the changes:

- All completion structures have been removed from the tmf and
abort paths.
- Now using one completed I/O list, with the I/O completed in host bit being
used to select error or normal callback paths.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c                |   86 +---
 drivers/scsi/isci/host.h                |    1 
 drivers/scsi/isci/init.c                |    1 
 drivers/scsi/isci/remote_device.c       |  255 +++++-----
 drivers/scsi/isci/remote_device.h       |   15 -
 drivers/scsi/isci/remote_node_context.c |   23 -
 drivers/scsi/isci/remote_node_context.h |    4 
 drivers/scsi/isci/request.c             |  509 ++++++---------------
 drivers/scsi/isci/request.h             |  108 ----
 drivers/scsi/isci/task.c                |  758 ++++---------------------------
 drivers/scsi/isci/task.h                |  132 -----
 11 files changed, 418 insertions(+), 1474 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index a43bc22..3cc2a23 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1078,33 +1078,25 @@ void isci_host_completion_routine(unsigned long data)
 {
 	struct isci_host *ihost = (struct isci_host *)data;
 	struct list_head    completed_request_list;
-	struct list_head    errored_request_list;
 	struct list_head    *current_position;
 	struct list_head    *next_position;
 	struct isci_request *request;
-	struct isci_request *next_request;
 	struct sas_task     *task;
 	u16 active;
 
 	INIT_LIST_HEAD(&completed_request_list);
-	INIT_LIST_HEAD(&errored_request_list);
 
 	spin_lock_irq(&ihost->scic_lock);
 
 	sci_controller_completion_handler(ihost);
 
 	/* Take the lists of completed I/Os from the host. */
-
 	list_splice_init(&ihost->requests_to_complete,
 			 &completed_request_list);
 
-	/* Take the list of errored I/Os from the host. */
-	list_splice_init(&ihost->requests_to_errorback,
-			 &errored_request_list);
-
 	spin_unlock_irq(&ihost->scic_lock);
 
-	/* Process any completions in the lists. */
+	/* Process any completions in the list. */
 	list_for_each_safe(current_position, next_position,
 			   &completed_request_list) {
 
@@ -1112,23 +1104,30 @@ void isci_host_completion_routine(unsigned long data)
 				     completed_node);
 		task = isci_request_access_task(request);
 
-		/* Normal notification (task_done) */
-		dev_dbg(&ihost->pdev->dev,
-			"%s: Normal - request/task = %p/%p\n",
-			__func__,
-			request,
-			task);
 
 		/* Return the task to libsas */
 		if (task != NULL) {
 
 			task->lldd_task = NULL;
-			if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-
-				/* If the task is already in the abort path,
-				* the task_done callback cannot be called.
-				*/
-				task->task_done(task);
+			if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags) &&
+			    !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+				if (test_bit(IREQ_COMPLETE_IN_TARGET,
+					     &request->flags)) {
+
+					/* Normal notification (task_done) */
+					dev_dbg(&ihost->pdev->dev, "%s: Normal"
+						" - request/task = %p/%p\n",
+						__func__, request, task);
+
+					task->task_done(task);
+				} else {
+					dev_warn(&ihost->pdev->dev,
+						 "%s: Error - request/task"
+						 " = %p/%p\n",
+						 __func__, request, task);
+
+					sas_task_abort(task);
+				}
 			}
 		}
 
@@ -1136,44 +1135,6 @@ void isci_host_completion_routine(unsigned long data)
 		isci_free_tag(ihost, request->io_tag);
 		spin_unlock_irq(&ihost->scic_lock);
 	}
-	list_for_each_entry_safe(request, next_request, &errored_request_list,
-				 completed_node) {
-
-		task = isci_request_access_task(request);
-
-		/* Use sas_task_abort */
-		dev_warn(&ihost->pdev->dev,
-			 "%s: Error - request/task = %p/%p\n",
-			 __func__,
-			 request,
-			 task);
-
-		if (task != NULL) {
-
-			/* Put the task into the abort path if it's not there
-			 * already.
-			 */
-			if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED))
-				sas_task_abort(task);
-
-		} else {
-			/* This is a case where the request has completed with a
-			 * status such that it needed further target servicing,
-			 * but the sas_task reference has already been removed
-			 * from the request.  Since it was errored, it was not
-			 * being aborted, so there is nothing to do except free
-			 * it.
-			 */
-
-			spin_lock_irq(&ihost->scic_lock);
-			/* Remove the request from the remote device's list
-			* of pending requests.
-			*/
-			list_del_init(&request->dev_node);
-			isci_free_tag(ihost, request->io_tag);
-			spin_unlock_irq(&ihost->scic_lock);
-		}
-	}
 
 	/* the coalesence timeout doubles at each encoding step, so
 	 * update it based on the ilog2 value of the outstanding requests
@@ -2329,7 +2290,6 @@ static int sci_controller_dma_alloc(struct isci_host *ihost)
 
 		ireq->tc = &ihost->task_context_table[i];
 		ireq->owning_controller = ihost;
-		spin_lock_init(&ireq->state_lock);
 		ireq->request_daddr = dma;
 		ireq->isci_host = ihost;
 		ihost->reqs[i] = ireq;
@@ -2679,6 +2639,10 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
 		return SCI_FAILURE_INVALID_STATE;
 	}
 	status = sci_io_request_terminate(ireq);
+
+	dev_dbg(&ihost->pdev->dev, "%s: status=%d; ireq=%p; flags=%lx\n",
+		__func__, status, ireq, ireq->flags);
+
 	if ((status == SCI_SUCCESS) &&
 	    !test_bit(IREQ_PENDING_ABORT, &ireq->flags) &&
 	    !test_and_set_bit(IREQ_TC_ABORT_POSTED, &ireq->flags)) {
@@ -2721,6 +2685,8 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost,
 
 		index = ISCI_TAG_TCI(ireq->io_tag);
 		clear_bit(IREQ_ACTIVE, &ireq->flags);
+		if (test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+			wake_up_all(&ihost->eventq);
 		return SCI_SUCCESS;
 	default:
 		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index a89c0e3..f8f2c9c 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -203,7 +203,6 @@ struct isci_host {
 	struct Scsi_Host *shost;
 	struct tasklet_struct completion_tasklet;
 	struct list_head requests_to_complete;
-	struct list_head requests_to_errorback;
 	spinlock_t scic_lock;
 	struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
 	struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 092e331..6fc72d8 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -560,7 +560,6 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
 	}
 
 	INIT_LIST_HEAD(&ihost->requests_to_complete);
-	INIT_LIST_HEAD(&ihost->requests_to_errorback);
 	for (i = 0; i < SCI_MAX_PORTS; i++) {
 		struct isci_port *iport = &ihost->ports[i];
 
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 3048e02..c47304c 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -81,49 +81,6 @@ static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev
 }
 
 /**
- * isci_remote_device_not_ready() - This function is called by the ihost when
- *    the remote device is not ready. We mark the isci device as ready (not
- *    "ready_for_io") and signal the waiting proccess.
- * @isci_host: This parameter specifies the isci host object.
- * @isci_device: This parameter specifies the remote device
- *
- * sci_lock is held on entrance to this function.
- */
-static void isci_remote_device_not_ready(struct isci_host *ihost,
-				  struct isci_remote_device *idev, u32 reason)
-{
-	struct isci_request *ireq;
-
-	dev_dbg(&ihost->pdev->dev,
-		"%s: isci_device = %p\n", __func__, idev);
-
-	switch (reason) {
-	case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
-		set_bit(IDEV_GONE, &idev->flags);
-		break;
-	case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
-		set_bit(IDEV_IO_NCQERROR, &idev->flags);
-
-		/* Suspend the remote device so the I/O can be terminated. */
-		sci_remote_device_suspend(idev);
-
-		/* Kill all outstanding requests for the device. */
-		list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) {
-
-			dev_dbg(&ihost->pdev->dev,
-				"%s: isci_device = %p request = %p\n",
-				__func__, idev, ireq);
-
-			sci_controller_terminate_request(ihost, idev, ireq);
-		}
-		/* Fall through into the default case... */
-	default:
-		clear_bit(IDEV_IO_READY, &idev->flags);
-		break;
-	}
-}
-
-/**
  * isci_remote_device_ready() - This function is called by the ihost when the
  *    remote device is ready. We mark the isci device as ready and signal the
  *    waiting proccess.
@@ -142,49 +99,121 @@ static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote
 		wake_up(&ihost->eventq);
 }
 
-static int isci_remote_device_suspendcheck(struct isci_remote_device *idev)
+static enum sci_status sci_remote_device_terminate_req(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	int check_abort,
+	struct isci_request *ireq)
+{
+	dev_dbg(&ihost->pdev->dev,
+		"%s: idev=%p; flags=%lx; req=%p; req target=%p\n",
+		__func__, idev, idev->flags, ireq, ireq->target_device);
+
+	if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
+	    (ireq->target_device != idev) ||
+	    (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags)))
+		return SCI_SUCCESS;
+
+	set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
+
+	return sci_controller_terminate_request(ihost, idev, ireq);
+}
+
+static enum sci_status sci_remote_device_terminate_reqs_checkabort(
+	struct isci_remote_device *idev,
+	int chk)
 {
-	return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-	    || !test_bit(IDEV_ALLOCATED, &idev->flags);
+	struct isci_host *ihost = idev->owning_port->owning_controller;
+	enum sci_status status  = SCI_SUCCESS;
+	u32 i;
+
+	for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
+		struct isci_request *ireq = ihost->reqs[i];
+		enum sci_status s;
+
+		s = sci_remote_device_terminate_req(ihost, idev, chk, ireq);
+		if (s != SCI_SUCCESS)
+			status = s;
+	}
+	return status;
 }
 
-enum sci_status isci_remote_device_suspend(
+enum sci_status isci_remote_device_terminate_requests(
 	struct isci_host *ihost,
-	struct isci_remote_device *idev)
+	struct isci_remote_device *idev,
+	struct isci_request *ireq)
 {
-	enum sci_status status;
+	enum sci_status status = SCI_SUCCESS;
 	unsigned long flags;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	if (isci_get_device(idev->domain_dev) == NULL) {
+	if (isci_get_device(idev) == NULL) {
+		dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n",
+			__func__, idev);
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		status = SCI_FAILURE;
 	} else {
-		status = sci_remote_device_suspend(idev);
-		spin_unlock_irqrestore(&ihost->scic_lock, flags);
-		if (status == SCI_SUCCESS) {
-			dev_dbg(&ihost->pdev->dev,
-				"%s: idev=%p, about to wait\n",
-				__func__, idev);
-			wait_event(ihost->eventq,
-				   isci_remote_device_suspendcheck(idev));
-			status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-					? SCI_SUCCESS : SCI_FAILURE;
-			dev_dbg(&ihost->pdev->dev,
-				"%s: idev=%p, wait done, device is %s\n",
-				__func__, idev,
-				test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
-					? "<suspended>" : "<deallocated!>");
+		dev_dbg(&ihost->pdev->dev,
+			"%s: idev=%p, ireq=%p; started_request_count=%d, "
+				"about to wait\n",
+			__func__, idev, ireq, idev->started_request_count);
+		if (ireq) {
+			/* Terminate a specific TC. */
+			sci_remote_device_terminate_req(ihost, idev, 0, ireq);
+			spin_unlock_irqrestore(&ihost->scic_lock, flags);
+			wait_event(ihost->eventq, !test_bit(IREQ_ACTIVE,
+							    &ireq->flags));
 
-		} else
-			dev_dbg(scirdev_to_dev(idev),
-				 "%s: sci_remote_device_suspend failed, "
-				 "status = %d\n", __func__, status);
+		} else {
+			/* Terminate all TCs. */
+			sci_remote_device_terminate_requests(idev);
+			spin_unlock_irqrestore(&ihost->scic_lock, flags);
+			wait_event(ihost->eventq,
+				   idev->started_request_count == 0);
+		}
+		dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
+			__func__, idev);
 		isci_put_device(idev);
 	}
 	return status;
 }
 
+/**
+* isci_remote_device_not_ready() - This function is called by the ihost when
+*    the remote device is not ready. We mark the isci device as ready (not
+*    "ready_for_io") and signal the waiting proccess.
+* @isci_host: This parameter specifies the isci host object.
+* @isci_device: This parameter specifies the remote device
+*
+* sci_lock is held on entrance to this function.
+*/
+static void isci_remote_device_not_ready(struct isci_host *ihost,
+					 struct isci_remote_device *idev,
+					 u32 reason)
+{
+	dev_dbg(&ihost->pdev->dev,
+		"%s: isci_device = %p\n", __func__, idev);
+
+	switch (reason) {
+	case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
+		set_bit(IDEV_GONE, &idev->flags);
+		break;
+	case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
+		set_bit(IDEV_IO_NCQERROR, &idev->flags);
+
+		/* Suspend the remote device so the I/O can be terminated. */
+		sci_remote_device_suspend(idev);
+
+		/* Kill all outstanding requests for the device. */
+		sci_remote_device_terminate_requests(idev);
+
+		/* Fall through into the default case... */
+	default:
+		clear_bit(IDEV_IO_READY, &idev->flags);
+		break;
+	}
+}
+
 /* called once the remote node context is ready to be freed.
  * The remote device can now report that its stop operation is complete. none
  */
@@ -196,36 +225,10 @@ static void rnc_destruct_done(void *_dev)
 	sci_change_state(&idev->sm, SCI_DEV_STOPPED);
 }
 
-static enum sci_status sci_remote_device_terminate_requests_checkabort(
-	struct isci_remote_device *idev,
-	int check_abort_pending)
-{
-	struct isci_host *ihost = idev->owning_port->owning_controller;
-	enum sci_status status  = SCI_SUCCESS;
-	u32 i;
-
-	for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
-		struct isci_request *ireq = ihost->reqs[i];
-		enum sci_status s;
-
-		if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
-		    (ireq->target_device != idev) ||
-		    (check_abort_pending && !test_bit(IREQ_PENDING_ABORT,
-						      &ireq->flags)))
-			continue;
-
-		s = sci_controller_terminate_request(ihost, idev, ireq);
-		if (s != SCI_SUCCESS)
-			status = s;
-	}
-
-	return status;
-}
-
 enum sci_status sci_remote_device_terminate_requests(
 	struct isci_remote_device *idev)
 {
-	return sci_remote_device_terminate_requests_checkabort(idev, 0);
+	return sci_remote_device_terminate_reqs_checkabort(idev, 0);
 }
 
 enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
@@ -771,10 +774,6 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
 		if (status != SCI_SUCCESS)
 			return status;
 
-		status = sci_remote_node_context_start_task(&idev->rnc, ireq);
-		if (status != SCI_SUCCESS)
-			goto out;
-
 		status = sci_request_start(ireq);
 		if (status != SCI_SUCCESS)
 			goto out;
@@ -796,8 +795,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
 		sci_remote_node_context_suspend(
 			&idev->rnc, SCI_SOFTWARE_SUSPENSION,
 			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
-		sci_remote_node_context_resume(
-			&idev->rnc, sci_remote_device_continue_request, idev);
+
+		status = sci_remote_node_context_start_task(&idev->rnc, ireq,
+				sci_remote_device_continue_request, idev);
 
 	out:
 		sci_remote_device_start_request(idev, ireq, status);
@@ -811,7 +811,9 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
 		if (status != SCI_SUCCESS)
 			return status;
 
-		status = sci_remote_node_context_start_task(&idev->rnc, ireq);
+		/* Resume the RNC as needed: */
+		status = sci_remote_node_context_start_task(&idev->rnc, ireq,
+							    NULL, NULL);
 		if (status != SCI_SUCCESS)
 			break;
 
@@ -1322,20 +1324,6 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport,
 	return status;
 }
 
-void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev)
-{
-	DECLARE_COMPLETION_ONSTACK(aborted_task_completion);
-
-	dev_dbg(&ihost->pdev->dev,
-		"%s: idev = %p\n", __func__, idev);
-
-	/* Cleanup all requests pending for this device. */
-	isci_terminate_pending_requests(ihost, idev);
-
-	dev_dbg(&ihost->pdev->dev,
-		"%s: idev = %p, done\n", __func__, idev);
-}
-
 /**
  * This function builds the isci_remote_device when a libsas dev_found message
  *    is received.
@@ -1495,32 +1483,28 @@ int isci_remote_device_found(struct domain_device *dev)
 	return status == SCI_SUCCESS ? 0 : -ENODEV;
 }
 
-enum sci_status isci_remote_device_reset(
+enum sci_status isci_remote_device_suspend_terminate(
 	struct isci_host *ihost,
-	struct isci_remote_device *idev)
+	struct isci_remote_device *idev,
+	struct isci_request *ireq)
 {
 	unsigned long flags;
 	enum sci_status status;
 
-	/* Put the device into a reset state so the suspension will not
-	 * automatically resume.
-	 */
+	/* Put the device into suspension. */
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	status = sci_remote_device_reset(idev);
+	sci_remote_device_suspend(idev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-	if (status != SCI_SUCCESS) {
-		dev_dbg(&ihost->pdev->dev,
-			"%s: sci_remote_device_reset(%p) returned %d!\n",
-			__func__, idev, status);
-		return status;
-	}
-	/* Wait for the device suspend. */
-	status = isci_remote_device_suspend(ihost, idev);
-	if (status != SCI_SUCCESS) {
+
+	/* Terminate and wait for the completions. */
+	status = isci_remote_device_terminate_requests(ihost, idev, ireq);
+	if (status != SCI_SUCCESS)
 		dev_dbg(&ihost->pdev->dev,
-			"%s: isci_remote_device_suspend(%p) returned %d!\n",
+			"%s: isci_remote_device_terminate_requests(%p) "
+				"returned %d!\n",
 			__func__, idev, status);
-	}
+
+	/* NOTE: RNC resumption is left to the caller! */
 	return status;
 }
 
@@ -1533,7 +1517,7 @@ int isci_remote_device_is_safe_to_abort(
 enum sci_status sci_remote_device_abort_requests_pending_abort(
 	struct isci_remote_device *idev)
 {
-	return sci_remote_device_terminate_requests_checkabort(idev, 1);
+	return sci_remote_device_terminate_reqs_checkabort(idev, 1);
 }
 
 enum sci_status isci_remote_device_reset_complete(
@@ -1545,7 +1529,6 @@ enum sci_status isci_remote_device_reset_complete(
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	status = sci_remote_device_reset_complete(idev);
-	sci_remote_device_resume(idev, NULL, NULL);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	return status;
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index a6a376e..da43698 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -85,7 +85,6 @@ struct isci_remote_device {
 	#define IDEV_GONE 3
 	#define IDEV_IO_READY 4
 	#define IDEV_IO_NCQERROR 5
-	#define IDEV_TXRX_SUSPENDED 6
 	unsigned long flags;
 	struct kref kref;
 	struct isci_port *isci_port;
@@ -107,10 +106,8 @@ struct isci_remote_device {
 
 /* device reference routines must be called under sci_lock */
 static inline struct isci_remote_device *isci_get_device(
-	struct domain_device *dev)
+	struct isci_remote_device *idev)
 {
-	struct isci_remote_device *idev = dev->lldd_dev;
-
 	if (idev)
 		kref_get(&idev->kref);
 	return idev;
@@ -378,4 +375,14 @@ enum sci_status isci_remote_device_reset(
 enum sci_status isci_remote_device_reset_complete(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_suspend_terminate(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	struct isci_request *ireq);
+
+enum sci_status isci_remote_device_terminate_requests(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	struct isci_request *ireq);
 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 7a8347e..feeca17 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -317,8 +317,6 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
 	struct isci_remote_device *idev = rnc_to_dev(rnc);
 	struct isci_host *ihost = idev->owning_port->owning_controller;
 
-	set_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
-
 	/* Terminate outstanding requests pending abort. */
 	sci_remote_device_abort_requests_pending_abort(idev);
 
@@ -326,16 +324,6 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
 	sci_remote_node_context_continue_state_transitions(rnc);
 }
 
-static void sci_remote_node_context_tx_rx_suspended_state_exit(
-	struct sci_base_state_machine *sm)
-{
-	struct sci_remote_node_context *rnc
-		= container_of(sm, typeof(*rnc), sm);
-	struct isci_remote_device *idev = rnc_to_dev(rnc);
-
-	clear_bit(IDEV_TXRX_SUSPENDED, &idev->flags);
-}
-
 static void sci_remote_node_context_await_suspend_state_exit(
 	struct sci_base_state_machine *sm)
 {
@@ -366,8 +354,6 @@ static const struct sci_base_state sci_remote_node_context_state_table[] = {
 	},
 	[SCI_RNC_TX_RX_SUSPENDED] = {
 		.enter_state = sci_remote_node_context_tx_rx_suspended_state_enter,
-		.exit_state
-			= sci_remote_node_context_tx_rx_suspended_state_exit,
 	},
 	[SCI_RNC_AWAIT_SUSPENSION] = {
 		.exit_state = sci_remote_node_context_await_suspend_state_exit,
@@ -671,8 +657,11 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context
 	}
 }
 
-enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
-							struct isci_request *ireq)
+enum sci_status sci_remote_node_context_start_task(
+	struct sci_remote_node_context *sci_rnc,
+	struct isci_request *ireq,
+	scics_sds_remote_node_context_callback cb_fn,
+	void *cb_p)
 {
 	enum scis_sds_remote_node_context_states state;
 
@@ -684,7 +673,7 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
 		return SCI_SUCCESS;
 	case SCI_RNC_TX_SUSPENDED:
 	case SCI_RNC_TX_RX_SUSPENDED:
-		sci_remote_node_context_resume(sci_rnc, NULL, NULL);
+		sci_remote_node_context_resume(sci_rnc, cb_fn, cb_p);
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 5ddf88b..2870af1 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -211,7 +211,9 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 						    scics_sds_remote_node_context_callback cb_fn,
 						    void *cb_p);
 enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
-							struct isci_request *ireq);
+						   struct isci_request *ireq,
+						   scics_sds_remote_node_context_callback cb_fn,
+						   void *cb_p);
 enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc,
 						      struct isci_request *ireq);
 int sci_remote_node_context_is_safe_to_abort(
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index d0386e1..2d27ebd 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2491,9 +2491,6 @@ static void isci_request_process_response_iu(
  * @request: This parameter is the completed isci_request object.
  * @response_ptr: This parameter specifies the service response for the I/O.
  * @status_ptr: This parameter specifies the exec status for the I/O.
- * @complete_to_host_ptr: This parameter specifies the action to be taken by
- *    the LLDD with respect to completing this request or forcing an abort
- *    condition on the I/O.
  * @open_rej_reason: This parameter specifies the encoded reason for the
  *    abandon-class reject.
  *
@@ -2504,14 +2501,12 @@ static void isci_request_set_open_reject_status(
 	struct sas_task *task,
 	enum service_response *response_ptr,
 	enum exec_status *status_ptr,
-	enum isci_completion_selection *complete_to_host_ptr,
 	enum sas_open_rej_reason open_rej_reason)
 {
 	/* Task in the target is done. */
 	set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 	*response_ptr                     = SAS_TASK_UNDELIVERED;
 	*status_ptr                       = SAS_OPEN_REJECT;
-	*complete_to_host_ptr             = isci_perform_normal_io_completion;
 	task->task_status.open_rej_reason = open_rej_reason;
 }
 
@@ -2521,9 +2516,6 @@ static void isci_request_set_open_reject_status(
  * @request: This parameter is the completed isci_request object.
  * @response_ptr: This parameter specifies the service response for the I/O.
  * @status_ptr: This parameter specifies the exec status for the I/O.
- * @complete_to_host_ptr: This parameter specifies the action to be taken by
- *    the LLDD with respect to completing this request or forcing an abort
- *    condition on the I/O.
  *
  * none.
  */
@@ -2532,8 +2524,7 @@ static void isci_request_handle_controller_specific_errors(
 	struct isci_request *request,
 	struct sas_task *task,
 	enum service_response *response_ptr,
-	enum exec_status *status_ptr,
-	enum isci_completion_selection *complete_to_host_ptr)
+	enum exec_status *status_ptr)
 {
 	unsigned int cstatus;
 
@@ -2574,9 +2565,6 @@ static void isci_request_handle_controller_specific_errors(
 				*status_ptr = SAS_ABORTED_TASK;
 
 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-			*complete_to_host_ptr =
-				isci_perform_normal_io_completion;
 		} else {
 			/* Task in the target is not done. */
 			*response_ptr = SAS_TASK_UNDELIVERED;
@@ -2587,9 +2575,6 @@ static void isci_request_handle_controller_specific_errors(
 				*status_ptr = SAM_STAT_TASK_ABORTED;
 
 			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-			*complete_to_host_ptr =
-				isci_perform_error_io_completion;
 		}
 
 		break;
@@ -2618,8 +2603,6 @@ static void isci_request_handle_controller_specific_errors(
 			*status_ptr = SAS_ABORTED_TASK;
 
 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-		*complete_to_host_ptr = isci_perform_normal_io_completion;
 		break;
 
 
@@ -2630,7 +2613,7 @@ static void isci_request_handle_controller_specific_errors(
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_WRONG_DEST);
+			SAS_OREJ_WRONG_DEST);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION:
@@ -2640,56 +2623,56 @@ static void isci_request_handle_controller_specific_errors(
 		 */
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_RESV_AB0);
+			SAS_OREJ_RESV_AB0);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_RESV_AB1);
+			SAS_OREJ_RESV_AB1);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_RESV_AB2);
+			SAS_OREJ_RESV_AB2);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_RESV_AB3);
+			SAS_OREJ_RESV_AB3);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_BAD_DESTINATION:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_BAD_DEST);
+			SAS_OREJ_BAD_DEST);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_STP_NORES);
+			SAS_OREJ_STP_NORES);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_EPROTO);
+			SAS_OREJ_EPROTO);
 		break;
 
 	case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED:
 
 		isci_request_set_open_reject_status(
 			request, task, response_ptr, status_ptr,
-			complete_to_host_ptr, SAS_OREJ_CONN_RATE);
+			SAS_OREJ_CONN_RATE);
 		break;
 
 	case SCU_TASK_DONE_LL_R_ERR:
@@ -2721,95 +2704,12 @@ static void isci_request_handle_controller_specific_errors(
 		*response_ptr = SAS_TASK_UNDELIVERED;
 		*status_ptr = SAM_STAT_TASK_ABORTED;
 
-		if (task->task_proto == SAS_PROTOCOL_SMP) {
+		if (task->task_proto == SAS_PROTOCOL_SMP)
 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-			*complete_to_host_ptr = isci_perform_normal_io_completion;
-		} else {
+		else
 			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-			*complete_to_host_ptr = isci_perform_error_io_completion;
-		}
-		break;
-	}
-}
-
-/**
- * isci_task_save_for_upper_layer_completion() - This function saves the
- *    request for later completion to the upper layer driver.
- * @host: This parameter is a pointer to the host on which the the request
- *    should be queued (either as an error or success).
- * @request: This parameter is the completed request.
- * @response: This parameter is the response code for the completed task.
- * @status: This parameter is the status code for the completed task.
- *
- * none.
- */
-static void isci_task_save_for_upper_layer_completion(
-	struct isci_host *host,
-	struct isci_request *request,
-	enum service_response response,
-	enum exec_status status,
-	enum isci_completion_selection task_notification_selection)
-{
-	struct sas_task *task = isci_request_access_task(request);
-
-	task_notification_selection
-		= isci_task_set_completion_status(task, response, status,
-						  task_notification_selection);
-
-	/* Tasks aborted specifically by a call to the lldd_abort_task
-	 * function should not be completed to the host in the regular path.
-	 */
-	switch (task_notification_selection) {
-
-	case isci_perform_normal_io_completion:
-		/* Normal notification (task_done) */
-
-		/* Add to the completed list. */
-		list_add(&request->completed_node,
-			 &host->requests_to_complete);
-
-		/* Take the request off the device's pending request list. */
-		list_del_init(&request->dev_node);
-		break;
-
-	case isci_perform_aborted_io_completion:
-		/* No notification to libsas because this request is
-		 * already in the abort path.
-		 */
-		/* Wake up whatever process was waiting for this
-		 * request to complete.
-		 */
-		WARN_ON(request->io_request_completion == NULL);
-
-		if (request->io_request_completion != NULL) {
-
-			/* Signal whoever is waiting that this
-			* request is complete.
-			*/
-			complete(request->io_request_completion);
-		}
-		break;
-
-	case isci_perform_error_io_completion:
-		/* Use sas_task_abort */
-		/* Add to the aborted list. */
-		list_add(&request->completed_node,
-			 &host->requests_to_errorback);
-		break;
-
-	default:
-		/* Add to the error to libsas list. */
-		list_add(&request->completed_node,
-			 &host->requests_to_errorback);
 		break;
 	}
-	dev_dbg(&host->pdev->dev,
-		"%s: %d - task = %p, response=%d (%d), status=%d (%d)\n",
-		__func__, task_notification_selection, task,
-		(task) ? task->task_status.resp : 0, response,
-		(task) ? task->task_status.stat : 0, status);
 }
 
 static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis)
@@ -2844,9 +2744,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 	struct isci_remote_device *idev = request->target_device;
 	enum service_response response = SAS_TASK_UNDELIVERED;
 	enum exec_status status = SAS_ABORTED_TASK;
-	enum isci_request_status request_status;
-	enum isci_completion_selection complete_to_host
-		= isci_perform_normal_io_completion;
 
 	dev_dbg(&ihost->pdev->dev,
 		"%s: request = %p, task = %p,\n"
@@ -2857,282 +2754,158 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 		task->data_dir,
 		completion_status);
 
-	spin_lock(&request->state_lock);
-	request_status = request->status;
-
-	/* Decode the request status.  Note that if the request has been
-	 * aborted by a task management function, we don't care
-	 * what the status is.
-	 */
-	switch (request_status) {
-
-	case aborted:
-		/* "aborted" indicates that the request was aborted by a task
-		 * management function, since once a task management request is
-		 * perfomed by the device, the request only completes because
-		 * of the subsequent driver terminate.
-		 *
-		 * Aborted also means an external thread is explicitly managing
-		 * this request, so that we do not complete it up the stack.
-		 *
-		 * The target is still there (since the TMF was successful).
-		 */
-		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-		response = SAS_TASK_COMPLETE;
+	/* The request is done from an SCU HW perspective. */
 
-		/* See if the device has been/is being stopped. Note
-		 * that we ignore the quiesce state, since we are
-		 * concerned about the actual device state.
-		 */
-		if (!idev)
-			status = SAS_DEVICE_UNKNOWN;
-		else
-			status = SAS_ABORTED_TASK;
+	/* This is an active request being completed from the core. */
+	switch (completion_status) {
 
-		complete_to_host = isci_perform_aborted_io_completion;
-		/* This was an aborted request. */
+	case SCI_IO_FAILURE_RESPONSE_VALID:
+		dev_dbg(&ihost->pdev->dev,
+			"%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
+			__func__, request, task);
 
-		spin_unlock(&request->state_lock);
-		break;
+		if (sas_protocol_ata(task->task_proto)) {
+			isci_process_stp_response(task, &request->stp.rsp);
+		} else if (SAS_PROTOCOL_SSP == task->task_proto) {
 
-	case aborting:
-		/* aborting means that the task management function tried and
-		 * failed to abort the request. We need to note the request
-		 * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the
-		 * target as down.
-		 *
-		 * Aborting also means an external thread is explicitly managing
-		 * this request, so that we do not complete it up the stack.
-		 */
-		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-		response = SAS_TASK_UNDELIVERED;
+			/* crack the iu response buffer. */
+			resp_iu = &request->ssp.rsp;
+			isci_request_process_response_iu(task, resp_iu,
+							 &ihost->pdev->dev);
 
-		if (!idev)
-			/* The device has been /is being stopped. Note that
-			 * we ignore the quiesce state, since we are
-			 * concerned about the actual device state.
-			 */
-			status = SAS_DEVICE_UNKNOWN;
-		else
-			status = SAS_PHY_DOWN;
+		} else if (SAS_PROTOCOL_SMP == task->task_proto) {
 
-		complete_to_host = isci_perform_aborted_io_completion;
+			dev_err(&ihost->pdev->dev,
+				"%s: SCI_IO_FAILURE_RESPONSE_VALID: "
+					"SAS_PROTOCOL_SMP protocol\n",
+				__func__);
 
-		/* This was an aborted request. */
+		} else
+			dev_err(&ihost->pdev->dev,
+				"%s: unknown protocol\n", __func__);
 
-		spin_unlock(&request->state_lock);
+		/* use the task status set in the task struct by the
+		* isci_request_process_response_iu call.
+		*/
+		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+		response = task->task_status.resp;
+		status = task->task_status.stat;
 		break;
 
-	case terminating:
+	case SCI_IO_SUCCESS:
+	case SCI_IO_SUCCESS_IO_DONE_EARLY:
 
-		/* This was an terminated request.  This happens when
-		 * the I/O is being terminated because of an action on
-		 * the device (reset, tear down, etc.), and the I/O needs
-		 * to be completed up the stack.
-		 */
+		response = SAS_TASK_COMPLETE;
+		status   = SAM_STAT_GOOD;
 		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-		response = SAS_TASK_UNDELIVERED;
 
-		/* See if the device has been/is being stopped. Note
-		 * that we ignore the quiesce state, since we are
-		 * concerned about the actual device state.
-		 */
-		if (!idev)
-			status = SAS_DEVICE_UNKNOWN;
-		else
-			status = SAS_ABORTED_TASK;
-
-		complete_to_host = isci_perform_aborted_io_completion;
-
-		/* This was a terminated request. */
-
-		spin_unlock(&request->state_lock);
-		break;
+		if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
 
-	case dead:
-		/* This was a terminated request that timed-out during the
-		 * termination process.  There is no task to complete to
-		 * libsas.
-		 */
-		complete_to_host = isci_perform_normal_io_completion;
-		spin_unlock(&request->state_lock);
-		break;
-
-	default:
-
-		/* The request is done from an SCU HW perspective. */
-		request->status = completed;
+			/* This was an SSP / STP / SATA transfer.
+			* There is a possibility that less data than
+			* the maximum was transferred.
+			*/
+			u32 transferred_length = sci_req_tx_bytes(request);
 
-		spin_unlock(&request->state_lock);
+			task->task_status.residual
+				= task->total_xfer_len - transferred_length;
 
-		/* This is an active request being completed from the core. */
-		switch (completion_status) {
+			/* If there were residual bytes, call this an
+			* underrun.
+			*/
+			if (task->task_status.residual != 0)
+				status = SAS_DATA_UNDERRUN;
 
-		case SCI_IO_FAILURE_RESPONSE_VALID:
 			dev_dbg(&ihost->pdev->dev,
-				"%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n",
-				__func__,
-				request,
-				task);
-
-			if (sas_protocol_ata(task->task_proto)) {
-				isci_process_stp_response(task, &request->stp.rsp);
-			} else if (SAS_PROTOCOL_SSP == task->task_proto) {
-
-				/* crack the iu response buffer. */
-				resp_iu = &request->ssp.rsp;
-				isci_request_process_response_iu(task, resp_iu,
-								 &ihost->pdev->dev);
-
-			} else if (SAS_PROTOCOL_SMP == task->task_proto) {
+				"%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
+				__func__, status);
 
-				dev_err(&ihost->pdev->dev,
-					"%s: SCI_IO_FAILURE_RESPONSE_VALID: "
-					"SAS_PROTOCOL_SMP protocol\n",
-					__func__);
-
-			} else
-				dev_err(&ihost->pdev->dev,
-					"%s: unknown protocol\n", __func__);
-
-			/* use the task status set in the task struct by the
-			 * isci_request_process_response_iu call.
-			 */
-			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-			response = task->task_status.resp;
-			status = task->task_status.stat;
-			break;
-
-		case SCI_IO_SUCCESS:
-		case SCI_IO_SUCCESS_IO_DONE_EARLY:
-
-			response = SAS_TASK_COMPLETE;
-			status   = SAM_STAT_GOOD;
-			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-
-			if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) {
-
-				/* This was an SSP / STP / SATA transfer.
-				 * There is a possibility that less data than
-				 * the maximum was transferred.
-				 */
-				u32 transferred_length = sci_req_tx_bytes(request);
-
-				task->task_status.residual
-					= task->total_xfer_len - transferred_length;
+		} else
+			dev_dbg(&ihost->pdev->dev, "%s: SCI_IO_SUCCESS\n",
+				__func__);
+		break;
 
-				/* If there were residual bytes, call this an
-				 * underrun.
-				 */
-				if (task->task_status.residual != 0)
-					status = SAS_DATA_UNDERRUN;
+	case SCI_IO_FAILURE_TERMINATED:
 
-				dev_dbg(&ihost->pdev->dev,
-					"%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n",
-					__func__,
-					status);
+		dev_dbg(&ihost->pdev->dev,
+			"%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
+			__func__, request, task);
 
-			} else
-				dev_dbg(&ihost->pdev->dev,
-					"%s: SCI_IO_SUCCESS\n",
-					__func__);
+		/* The request was terminated explicitly. */
+		clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+		response = SAS_TASK_UNDELIVERED;
 
-			break;
+		/* See if the device has been/is being stopped. Note
+		* that we ignore the quiesce state, since we are
+		* concerned about the actual device state.
+		*/
+		if (!idev)
+			status = SAS_DEVICE_UNKNOWN;
+		else
+			status = SAS_ABORTED_TASK;
+		break;
 
-		case SCI_IO_FAILURE_TERMINATED:
-			dev_dbg(&ihost->pdev->dev,
-				"%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n",
-				__func__,
-				request,
-				task);
+	case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
 
-			/* The request was terminated explicitly.  No handling
-			 * is needed in the SCSI error handler path.
-			 */
-			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-			response = SAS_TASK_UNDELIVERED;
+		isci_request_handle_controller_specific_errors(idev, request,
+							       task, &response,
+							       &status);
+		break;
 
-			/* See if the device has been/is being stopped. Note
-			 * that we ignore the quiesce state, since we are
-			 * concerned about the actual device state.
-			 */
-			if (!idev)
-				status = SAS_DEVICE_UNKNOWN;
-			else
-				status = SAS_ABORTED_TASK;
+	case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
+		/* This is a special case, in that the I/O completion
+		* is telling us that the device needs a reset.
+		* In order for the device reset condition to be
+		* noticed, the I/O has to be handled in the error
+		* handler.  Set the reset flag and cause the
+		* SCSI error thread to be scheduled.
+		*/
+		spin_lock_irqsave(&task->task_state_lock, task_flags);
+		task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+		spin_unlock_irqrestore(&task->task_state_lock, task_flags);
 
-			complete_to_host = isci_perform_normal_io_completion;
-			break;
+		/* Fail the I/O. */
+		response = SAS_TASK_UNDELIVERED;
+		status = SAM_STAT_TASK_ABORTED;
 
-		case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR:
+		clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+		break;
 
-			isci_request_handle_controller_specific_errors(
-				idev, request, task, &response, &status,
-				&complete_to_host);
+	case SCI_FAILURE_RETRY_REQUIRED:
 
-			break;
+		/* Fail the I/O so it can be retried. */
+		response = SAS_TASK_UNDELIVERED;
+		if (!idev)
+			status = SAS_DEVICE_UNKNOWN;
+		else
+			status = SAS_ABORTED_TASK;
 
-		case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED:
-			/* This is a special case, in that the I/O completion
-			 * is telling us that the device needs a reset.
-			 * In order for the device reset condition to be
-			 * noticed, the I/O has to be handled in the error
-			 * handler.  Set the reset flag and cause the
-			 * SCSI error thread to be scheduled.
-			 */
-			spin_lock_irqsave(&task->task_state_lock, task_flags);
-			task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
-			spin_unlock_irqrestore(&task->task_state_lock, task_flags);
+		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+		break;
 
-			/* Fail the I/O. */
-			response = SAS_TASK_UNDELIVERED;
-			status = SAM_STAT_TASK_ABORTED;
 
-			complete_to_host = isci_perform_error_io_completion;
-			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-			break;
+	default:
+		/* Catch any otherwise unhandled error codes here. */
+		dev_dbg(&ihost->pdev->dev,
+			"%s: invalid completion code: 0x%x - "
+				"isci_request = %p\n",
+			__func__, completion_status, request);
 
-		case SCI_FAILURE_RETRY_REQUIRED:
+		response = SAS_TASK_UNDELIVERED;
 
-			/* Fail the I/O so it can be retried. */
-			response = SAS_TASK_UNDELIVERED;
-			if (!idev)
-				status = SAS_DEVICE_UNKNOWN;
-			else
-				status = SAS_ABORTED_TASK;
+		/* See if the device has been/is being stopped. Note
+		* that we ignore the quiesce state, since we are
+		* concerned about the actual device state.
+		*/
+		if (!idev)
+			status = SAS_DEVICE_UNKNOWN;
+		else
+			status = SAS_ABORTED_TASK;
 
-			complete_to_host = isci_perform_normal_io_completion;
+		if (SAS_PROTOCOL_SMP == task->task_proto)
 			set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-			break;
-
-
-		default:
-			/* Catch any otherwise unhandled error codes here. */
-			dev_dbg(&ihost->pdev->dev,
-				 "%s: invalid completion code: 0x%x - "
-				 "isci_request = %p\n",
-				 __func__, completion_status, request);
-
-			response = SAS_TASK_UNDELIVERED;
-
-			/* See if the device has been/is being stopped. Note
-			 * that we ignore the quiesce state, since we are
-			 * concerned about the actual device state.
-			 */
-			if (!idev)
-				status = SAS_DEVICE_UNKNOWN;
-			else
-				status = SAS_ABORTED_TASK;
-
-			if (SAS_PROTOCOL_SMP == task->task_proto) {
-				set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-				complete_to_host = isci_perform_normal_io_completion;
-			} else {
-				clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
-				complete_to_host = isci_perform_error_io_completion;
-			}
-			break;
-		}
+		else
+			clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 		break;
 	}
 
@@ -3167,10 +2940,24 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 		break;
 	}
 
-	/* Put the completed request on the correct list */
-	isci_task_save_for_upper_layer_completion(ihost, request, response,
-						  status, complete_to_host
-						  );
+	spin_lock_irqsave(&task->task_state_lock, task_flags);
+
+	task->task_status.resp = response;
+	task->task_status.stat = status;
+
+	if (test_bit(IREQ_COMPLETE_IN_TARGET, &request->flags)) {
+		/* Normal notification (task_done) */
+		task->task_state_flags |= SAS_TASK_STATE_DONE;
+		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+					    SAS_TASK_STATE_PENDING);
+	}
+	spin_unlock_irqrestore(&task->task_state_lock, task_flags);
+
+	/* Add to the completed list. */
+	list_add(&request->completed_node, &ihost->requests_to_complete);
+
+	/* Take the request off the device's pending request list. */
+	list_del_init(&request->dev_node);
 
 	/* complete the io request to the core. */
 	sci_controller_complete_io(ihost, request->target_device, request);
@@ -3626,7 +3413,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t
 	ireq->num_sg_entries = 0;
 	INIT_LIST_HEAD(&ireq->completed_node);
 	INIT_LIST_HEAD(&ireq->dev_node);
-	isci_request_change_state(ireq, allocated);
 
 	return ireq;
 }
@@ -3721,15 +3507,12 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
 	 */
 	list_add(&ireq->dev_node, &idev->reqs_in_process);
 
-	if (status == SCI_SUCCESS) {
-		isci_request_change_state(ireq, started);
-	} else {
+	if (status != SCI_SUCCESS) {
 		/* The request did not really start in the
 		 * hardware, so clear the request handle
 		 * here so no terminations will be done.
 		 */
 		set_bit(IREQ_TERMINATED, &ireq->flags);
-		isci_request_change_state(ireq, completed);
 	}
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 8d55f78..f3116a5 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -61,23 +61,6 @@
 #include "scu_task_context.h"
 
 /**
- * struct isci_request_status - This enum defines the possible states of an I/O
- *    request.
- *
- *
- */
-enum isci_request_status {
-	unallocated = 0x00,
-	allocated   = 0x01,
-	started     = 0x02,
-	completed   = 0x03,
-	aborting    = 0x04,
-	aborted     = 0x05,
-	terminating = 0x06,
-	dead        = 0x07
-};
-
-/**
  * isci_stp_request - extra request infrastructure to handle pio/atapi protocol
  * @pio_len - number of bytes requested at PIO setup
  * @status - pio setup ending status value to tell us if we need
@@ -97,13 +80,13 @@ struct isci_stp_request {
 };
 
 struct isci_request {
-	enum isci_request_status status;
 	#define IREQ_COMPLETE_IN_TARGET 0
 	#define IREQ_TERMINATED 1
 	#define IREQ_TMF 2
 	#define IREQ_ACTIVE 3
 	#define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
 	#define IREQ_TC_ABORT_POSTED 5
+	#define IREQ_ABORT_PATH_ACTIVE 6
 	unsigned long flags;
 	/* XXX kill ttype and ttype_ptr, allocate full sas_task */
 	union ttype_ptr_union {
@@ -115,7 +98,6 @@ struct isci_request {
 	struct list_head completed_node;
 	/* For use in the reqs_in_process list: */
 	struct list_head dev_node;
-	spinlock_t state_lock;
 	dma_addr_t request_daddr;
 	dma_addr_t zero_scatter_daddr;
 	unsigned int num_sg_entries;
@@ -304,92 +286,6 @@ sci_io_request_get_dma_addr(struct isci_request *ireq, void *virt_addr)
 	return ireq->request_daddr + (requested_addr - base_addr);
 }
 
-/**
- * isci_request_change_state() - This function sets the status of the request
- *    object.
- * @request: This parameter points to the isci_request object
- * @status: This Parameter is the new status of the object
- *
- */
-static inline enum isci_request_status
-isci_request_change_state(struct isci_request *isci_request,
-			  enum isci_request_status status)
-{
-	enum isci_request_status old_state;
-	unsigned long flags;
-
-	dev_dbg(&isci_request->isci_host->pdev->dev,
-		"%s: isci_request = %p, state = 0x%x\n",
-		__func__,
-		isci_request,
-		status);
-
-	BUG_ON(isci_request == NULL);
-
-	spin_lock_irqsave(&isci_request->state_lock, flags);
-	old_state = isci_request->status;
-	isci_request->status = status;
-	spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
-	return old_state;
-}
-
-/**
- * isci_request_change_started_to_newstate() - This function sets the status of
- *    the request object.
- * @request: This parameter points to the isci_request object
- * @status: This Parameter is the new status of the object
- *
- * state previous to any change.
- */
-static inline enum isci_request_status
-isci_request_change_started_to_newstate(struct isci_request *isci_request,
-					struct completion *completion_ptr,
-					enum isci_request_status newstate)
-{
-	enum isci_request_status old_state;
-	unsigned long flags;
-
-	spin_lock_irqsave(&isci_request->state_lock, flags);
-
-	old_state = isci_request->status;
-
-	if (old_state == started || old_state == aborting) {
-		BUG_ON(isci_request->io_request_completion != NULL);
-
-		isci_request->io_request_completion = completion_ptr;
-		isci_request->status = newstate;
-	}
-
-	spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
-	dev_dbg(&isci_request->isci_host->pdev->dev,
-		"%s: isci_request = %p, old_state = 0x%x\n",
-		__func__,
-		isci_request,
-		old_state);
-
-	return old_state;
-}
-
-/**
- * isci_request_change_started_to_aborted() - This function sets the status of
- *    the request object.
- * @request: This parameter points to the isci_request object
- * @completion_ptr: This parameter is saved as the kernel completion structure
- *    signalled when the old request completes.
- *
- * state previous to any change.
- */
-static inline enum isci_request_status
-isci_request_change_started_to_aborted(struct isci_request *isci_request,
-				       struct completion *completion_ptr)
-{
-	return isci_request_change_started_to_newstate(isci_request,
-						       completion_ptr,
-						       aborted);
-}
-
 #define isci_request_access_task(req) ((req)->ttype_ptr.io_task_ptr)
 
 #define isci_request_access_tmf(req) ((req)->ttype_ptr.tmf_task_ptr)
@@ -399,8 +295,6 @@ struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost,
 					       u16 tag);
 int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev,
 			 struct sas_task *task, u16 tag);
-void isci_terminate_pending_requests(struct isci_host *ihost,
-				     struct isci_remote_device *idev);
 enum sci_status
 sci_task_request_construct(struct isci_host *ihost,
 			    struct isci_remote_device *idev,
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 26de06e..29ce881 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -78,54 +78,25 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
 			     enum exec_status status)
 
 {
-	enum isci_completion_selection disposition;
+	unsigned long flags;
 
-	disposition = isci_perform_normal_io_completion;
-	disposition = isci_task_set_completion_status(task, response, status,
-						      disposition);
+	/* Normal notification (task_done) */
+	dev_dbg(&ihost->pdev->dev, "%s: task = %p, response=%d, status=%d\n",
+		__func__, task, response, status);
 
-	/* Tasks aborted specifically by a call to the lldd_abort_task
-	 * function should not be completed to the host in the regular path.
-	 */
-	switch (disposition) {
-	case isci_perform_normal_io_completion:
-		/* Normal notification (task_done) */
-		dev_dbg(&ihost->pdev->dev,
-			"%s: Normal - task = %p, response=%d, "
-			"status=%d\n",
-			__func__, task, response, status);
-
-		task->lldd_task = NULL;
-		task->task_done(task);
-		break;
-
-	case isci_perform_aborted_io_completion:
-		/*
-		 * No notification because this request is already in the
-		 * abort path.
-		 */
-		dev_dbg(&ihost->pdev->dev,
-			"%s: Aborted - task = %p, response=%d, "
-			"status=%d\n",
-			__func__, task, response, status);
-		break;
+	spin_lock_irqsave(&task->task_state_lock, flags);
 
-	case isci_perform_error_io_completion:
-		/* Use sas_task_abort */
-		dev_dbg(&ihost->pdev->dev,
-			"%s: Error - task = %p, response=%d, "
-			"status=%d\n",
-			__func__, task, response, status);
-		sas_task_abort(task);
-		break;
+	task->task_status.resp = response;
+	task->task_status.stat = status;
 
-	default:
-		dev_dbg(&ihost->pdev->dev,
-			"%s: isci task notification default case!",
-			__func__);
-		sas_task_abort(task);
-		break;
-	}
+	/* Normal notification (task_done) */
+	task->task_state_flags |= SAS_TASK_STATE_DONE;
+	task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+				    SAS_TASK_STATE_PENDING);
+	task->lldd_task = NULL;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	task->task_done(task);
 }
 
 #define for_each_sas_task(num, task) \
@@ -289,60 +260,6 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost,
 	return ireq;
 }
 
-/**
-* isci_request_mark_zombie() - This function must be called with scic_lock held.
-*/
-static void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq)
-{
-	struct completion *tmf_completion = NULL;
-	struct completion *req_completion;
-
-	/* Set the request state to "dead". */
-	ireq->status = dead;
-
-	req_completion = ireq->io_request_completion;
-	ireq->io_request_completion = NULL;
-
-	if (test_bit(IREQ_TMF, &ireq->flags)) {
-		/* Break links with the TMF request. */
-		struct isci_tmf *tmf = isci_request_access_tmf(ireq);
-
-		/* In the case where a task request is dying,
-		 * the thread waiting on the complete will sit and
-		 * timeout unless we wake it now.  Since the TMF
-		 * has a default error status, complete it here
-		 * to wake the waiting thread.
-		 */
-		if (tmf) {
-			tmf_completion = tmf->complete;
-			tmf->complete = NULL;
-		}
-		ireq->ttype_ptr.tmf_task_ptr = NULL;
-		dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n",
-			__func__, tmf->tmf_code, tmf->io_tag);
-	} else {
-		/* Break links with the sas_task - the callback is done
-		 * elsewhere.
-		 */
-		struct sas_task *task = isci_request_access_task(ireq);
-
-		if (task)
-			task->lldd_task = NULL;
-
-		ireq->ttype_ptr.io_task_ptr = NULL;
-	}
-
-	dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n",
-		 ireq->io_tag);
-
-	/* Don't force waiting threads to timeout. */
-	if (req_completion)
-		complete(req_completion);
-
-	if (tmf_completion != NULL)
-		complete(tmf_completion);
-}
-
 static int isci_task_execute_tmf(struct isci_host *ihost,
 				 struct isci_remote_device *idev,
 				 struct isci_tmf *tmf, unsigned long timeout_ms)
@@ -400,15 +317,12 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		goto err_tci;
 	}
-
-	if (tmf->cb_state_func != NULL)
-		tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data);
-
-	isci_request_change_state(ireq, started);
-
 	/* add the request to the remote device request list. */
 	list_add(&ireq->dev_node, &idev->reqs_in_process);
 
+	/* The RNC must be unsuspended before the TMF can get a response. */
+	sci_remote_device_resume(idev, NULL, NULL);
+
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	/* Wait for the TMF to complete, or a timeout. */
@@ -419,32 +333,7 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
 		/* The TMF did not complete - this could be because
 		 * of an unplug.  Terminate the TMF request now.
 		 */
-		spin_lock_irqsave(&ihost->scic_lock, flags);
-
-		if (tmf->cb_state_func != NULL)
-			tmf->cb_state_func(isci_tmf_timed_out, tmf,
-					   tmf->cb_data);
-
-		sci_controller_terminate_request(ihost, idev, ireq);
-
-		spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-		timeleft = wait_for_completion_timeout(
-			&completion,
-			msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
-
-		if (!timeleft) {
-			/* Strange condition - the termination of the TMF
-			 * request timed-out.
-			 */
-			spin_lock_irqsave(&ihost->scic_lock, flags);
-
-			/* If the TMF status has not changed, kill it. */
-			if (tmf->status == SCI_FAILURE_TIMEOUT)
-				isci_request_mark_zombie(ihost, ireq);
-
-			spin_unlock_irqrestore(&ihost->scic_lock, flags);
-		}
+		isci_remote_device_suspend_terminate(ihost, idev, ireq);
 	}
 
 	isci_print_tmf(ihost, tmf);
@@ -476,317 +365,21 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
 }
 
 static void isci_task_build_tmf(struct isci_tmf *tmf,
-				enum isci_tmf_function_codes code,
-				void (*tmf_sent_cb)(enum isci_tmf_cb_state,
-						    struct isci_tmf *,
-						    void *),
-				void *cb_data)
+				enum isci_tmf_function_codes code)
 {
 	memset(tmf, 0, sizeof(*tmf));
-
-	tmf->tmf_code      = code;
-	tmf->cb_state_func = tmf_sent_cb;
-	tmf->cb_data       = cb_data;
+	tmf->tmf_code = code;
 }
 
 static void isci_task_build_abort_task_tmf(struct isci_tmf *tmf,
 					   enum isci_tmf_function_codes code,
-					   void (*tmf_sent_cb)(enum isci_tmf_cb_state,
-							       struct isci_tmf *,
-							       void *),
 					   struct isci_request *old_request)
 {
-	isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request);
+	isci_task_build_tmf(tmf, code);
 	tmf->io_tag = old_request->io_tag;
 }
 
 /**
- * isci_task_validate_request_to_abort() - This function checks the given I/O
- *    against the "started" state.  If the request is still "started", it's
- *    state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD
- *    BEFORE CALLING THIS FUNCTION.
- * @isci_request: This parameter specifies the request object to control.
- * @isci_host: This parameter specifies the ISCI host object
- * @isci_device: This is the device to which the request is pending.
- * @aborted_io_completion: This is a completion structure that will be added to
- *    the request in case it is changed to aborting; this completion is
- *    triggered when the request is fully completed.
- *
- * Either "started" on successful change of the task status to "aborted", or
- * "unallocated" if the task cannot be controlled.
- */
-static enum isci_request_status isci_task_validate_request_to_abort(
-	struct isci_request *isci_request,
-	struct isci_host *isci_host,
-	struct isci_remote_device *isci_device,
-	struct completion *aborted_io_completion)
-{
-	enum isci_request_status old_state = unallocated;
-
-	/* Only abort the task if it's in the
-	 *  device's request_in_process list
-	 */
-	if (isci_request && !list_empty(&isci_request->dev_node)) {
-		old_state = isci_request_change_started_to_aborted(
-			isci_request, aborted_io_completion);
-
-	}
-
-	return old_state;
-}
-
-static int isci_request_is_dealloc_managed(enum isci_request_status stat)
-{
-	switch (stat) {
-	case aborted:
-	case aborting:
-	case terminating:
-	case completed:
-	case dead:
-		return true;
-	default:
-		return false;
-	}
-}
-
-/**
- * isci_terminate_request_core() - This function will terminate the given
- *    request, and wait for it to complete.  This function must only be called
- *    from a thread that can wait.  Note that the request is terminated and
- *    completed (back to the host, if started there).
- * @ihost: This SCU.
- * @idev: The target.
- * @isci_request: The I/O request to be terminated.
- *
- */
-static void isci_terminate_request_core(struct isci_host *ihost,
-					struct isci_remote_device *idev,
-					struct isci_request *isci_request)
-{
-	enum sci_status status      = SCI_SUCCESS;
-	bool was_terminated         = false;
-	bool needs_cleanup_handling = false;
-	unsigned long     flags;
-	unsigned long     termination_completed = 1;
-	struct completion *io_request_completion;
-
-	dev_dbg(&ihost->pdev->dev,
-		"%s: device = %p; request = %p\n",
-		__func__, idev, isci_request);
-
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-
-	io_request_completion = isci_request->io_request_completion;
-
-	/* Note that we are not going to control
-	 * the target to abort the request.
-	 */
-	set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->flags);
-
-	/* Make sure the request wasn't just sitting around signalling
-	 * device condition (if the request handle is NULL, then the
-	 * request completed but needed additional handling here).
-	 */
-	if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) {
-		was_terminated = true;
-		needs_cleanup_handling = true;
-		status = sci_controller_terminate_request(ihost,
-							   idev,
-							   isci_request);
-	}
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-	/*
-	 * The only time the request to terminate will
-	 * fail is when the io request is completed and
-	 * being aborted.
-	 */
-	if (status != SCI_SUCCESS) {
-		dev_dbg(&ihost->pdev->dev,
-			"%s: sci_controller_terminate_request"
-			" returned = 0x%x\n",
-			__func__, status);
-
-		isci_request->io_request_completion = NULL;
-
-	} else {
-		if (was_terminated) {
-			dev_dbg(&ihost->pdev->dev,
-				"%s: before completion wait (%p/%p)\n",
-				__func__, isci_request, io_request_completion);
-
-			/* Wait here for the request to complete. */
-			termination_completed
-				= wait_for_completion_timeout(
-				   io_request_completion,
-				   msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC));
-
-			if (!termination_completed) {
-
-				/* The request to terminate has timed out.  */
-				spin_lock_irqsave(&ihost->scic_lock, flags);
-
-				/* Check for state changes. */
-				if (!test_bit(IREQ_TERMINATED,
-					      &isci_request->flags)) {
-
-					/* The best we can do is to have the
-					 * request die a silent death if it
-					 * ever really completes.
-					 */
-					isci_request_mark_zombie(ihost,
-								 isci_request);
-					needs_cleanup_handling = true;
-				} else
-					termination_completed = 1;
-
-				spin_unlock_irqrestore(&ihost->scic_lock,
-						       flags);
-
-				if (!termination_completed) {
-
-					dev_dbg(&ihost->pdev->dev,
-						"%s: *** Timeout waiting for "
-						"termination(%p/%p)\n",
-						__func__, io_request_completion,
-						isci_request);
-
-					/* The request can no longer be referenced
-					 * safely since it may go away if the
-					 * termination every really does complete.
-					 */
-					isci_request = NULL;
-				}
-			}
-			if (termination_completed)
-				dev_dbg(&ihost->pdev->dev,
-					"%s: after completion wait (%p/%p)\n",
-					__func__, isci_request, io_request_completion);
-		}
-
-		if (termination_completed) {
-
-			isci_request->io_request_completion = NULL;
-
-			/* Peek at the status of the request.  This will tell
-			 * us if there was special handling on the request such that it
-			 * needs to be detached and freed here.
-			 */
-			spin_lock_irqsave(&isci_request->state_lock, flags);
-
-			needs_cleanup_handling
-				= isci_request_is_dealloc_managed(
-					isci_request->status);
-
-			spin_unlock_irqrestore(&isci_request->state_lock, flags);
-
-		}
-		if (needs_cleanup_handling) {
-
-			dev_dbg(&ihost->pdev->dev,
-				"%s: cleanup isci_device=%p, request=%p\n",
-				__func__, idev, isci_request);
-
-			if (isci_request != NULL) {
-				spin_lock_irqsave(&ihost->scic_lock, flags);
-				isci_free_tag(ihost, isci_request->io_tag);
-				isci_request_change_state(isci_request, unallocated);
-				list_del_init(&isci_request->dev_node);
-				spin_unlock_irqrestore(&ihost->scic_lock, flags);
-			}
-		}
-	}
-}
-
-/**
- * isci_terminate_pending_requests() - This function will change the all of the
- *    requests on the given device's state to "aborting", will terminate the
- *    requests, and wait for them to complete.  This function must only be
- *    called from a thread that can wait.  Note that the requests are all
- *    terminated and completed (back to the host, if started there).
- * @isci_host: This parameter specifies SCU.
- * @idev: This parameter specifies the target.
- *
- */
-void isci_terminate_pending_requests(struct isci_host *ihost,
-				     struct isci_remote_device *idev)
-{
-	struct completion request_completion;
-	enum isci_request_status old_state;
-	unsigned long flags;
-	LIST_HEAD(list);
-
-	isci_remote_device_suspend(ihost, idev);
-
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-	list_splice_init(&idev->reqs_in_process, &list);
-
-	/* assumes that isci_terminate_request_core deletes from the list */
-	while (!list_empty(&list)) {
-		struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node);
-
-		/* Change state to "terminating" if it is currently
-		 * "started".
-		 */
-		old_state = isci_request_change_started_to_newstate(ireq,
-								    &request_completion,
-								    terminating);
-		switch (old_state) {
-		case started:
-		case completed:
-		case aborting:
-			break;
-		default:
-			/* termination in progress, or otherwise dispositioned.
-			 * We know the request was on 'list' so should be safe
-			 * to move it back to reqs_in_process
-			 */
-			list_move(&ireq->dev_node, &idev->reqs_in_process);
-			ireq = NULL;
-			break;
-		}
-
-		if (!ireq)
-			continue;
-		spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
-		init_completion(&request_completion);
-
-		dev_dbg(&ihost->pdev->dev,
-			 "%s: idev=%p request=%p; task=%p old_state=%d\n",
-			 __func__, idev, ireq,
-			(!test_bit(IREQ_TMF, &ireq->flags)
-				? isci_request_access_task(ireq)
-				: NULL),
-			old_state);
-
-		/* If the old_state is started:
-		 * This request was not already being aborted. If it had been,
-		 * then the aborting I/O (ie. the TMF request) would not be in
-		 * the aborting state, and thus would be terminated here.  Note
-		 * that since the TMF completion's call to the kernel function
-		 * "complete()" does not happen until the pending I/O request
-		 * terminate fully completes, we do not have to implement a
-		 * special wait here for already aborting requests - the
-		 * termination of the TMF request will force the request
-		 * to finish it's already started terminate.
-		 *
-		 * If old_state == completed:
-		 * This request completed from the SCU hardware perspective
-		 * and now just needs cleaning up in terms of freeing the
-		 * request and potentially calling up to libsas.
-		 *
-		 * If old_state == aborting:
-		 * This request has already gone through a TMF timeout, but may
-		 * not have been terminated; needs cleaning up at least.
-		 */
-		isci_terminate_request_core(ihost, idev, ireq);
-		spin_lock_irqsave(&ihost->scic_lock, flags);
-	}
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-}
-
-/**
  * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain
  *    Template functions.
  * @lun: This parameter specifies the lun to be reset.
@@ -809,7 +402,7 @@ static int isci_task_send_lu_reset_sas(
 	 * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or
 	 * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED").
 	 */
-	isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL);
+	isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset);
 
 	#define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */
 	ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS);
@@ -829,48 +422,41 @@ static int isci_task_send_lu_reset_sas(
 int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 {
 	struct isci_host *ihost = dev_to_ihost(dev);
-	struct isci_remote_device *isci_device;
+	struct isci_remote_device *idev;
 	unsigned long flags;
 	int ret;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	isci_device = isci_lookup_device(dev);
+	idev = isci_lookup_device(dev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	dev_dbg(&ihost->pdev->dev,
 		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
-		__func__, dev, ihost, isci_device);
+		__func__, dev, ihost, idev);
 
-	if (!isci_device) {
+	if (!idev) {
 		/* If the device is gone, escalate to I_T_Nexus_Reset. */
 		dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__);
 
 		ret = TMF_RESP_FUNC_FAILED;
 		goto out;
 	}
-	if (isci_remote_device_suspend(ihost, isci_device) != SCI_SUCCESS) {
-		dev_dbg(&ihost->pdev->dev,
-			"%s:  device = %p; failed to suspend\n",
-			__func__, isci_device);
-		ret = TMF_RESP_FUNC_FAILED;
-		goto out;
-	}
 
-	/* Send the task management part of the reset. */
 	if (dev_is_sata(dev)) {
 		sas_ata_schedule_reset(dev);
 		ret = TMF_RESP_FUNC_COMPLETE;
-	} else
-		ret = isci_task_send_lu_reset_sas(ihost, isci_device, lun);
-
-	/* If the LUN reset worked, all the I/O can now be terminated. */
-	if (ret == TMF_RESP_FUNC_COMPLETE) {
-		/* Terminate all I/O now. */
-		isci_terminate_pending_requests(ihost, isci_device);
-		isci_remote_device_resume(ihost, isci_device, NULL, NULL);
+	} else {
+		/* Suspend the RNC, kill all TCs */
+		if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+		    != SCI_SUCCESS) {
+			ret = TMF_RESP_FUNC_FAILED;
+			goto out;
+		}
+		/* Send the task management part of the reset. */
+		ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
 	}
  out:
-	isci_put_device(isci_device);
+	isci_put_device(idev);
 	return ret;
 }
 
@@ -891,63 +477,6 @@ int isci_task_clear_nexus_ha(struct sas_ha_struct *ha)
 /* Task Management Functions. Must be called from process context.	 */
 
 /**
- * isci_abort_task_process_cb() - This is a helper function for the abort task
- *    TMF command.  It manages the request state with respect to the successful
- *    transmission / completion of the abort task request.
- * @cb_state: This parameter specifies when this function was called - after
- *    the TMF request has been started and after it has timed-out.
- * @tmf: This parameter specifies the TMF in progress.
- *
- *
- */
-static void isci_abort_task_process_cb(
-	enum isci_tmf_cb_state cb_state,
-	struct isci_tmf *tmf,
-	void *cb_data)
-{
-	struct isci_request *old_request;
-
-	old_request = (struct isci_request *)cb_data;
-
-	dev_dbg(&old_request->isci_host->pdev->dev,
-		"%s: tmf=%p, old_request=%p\n",
-		__func__, tmf, old_request);
-
-	switch (cb_state) {
-
-	case isci_tmf_started:
-		/* The TMF has been started.  Nothing to do here, since the
-		 * request state was already set to "aborted" by the abort
-		 * task function.
-		 */
-		if ((old_request->status != aborted)
-			&& (old_request->status != completed))
-			dev_dbg(&old_request->isci_host->pdev->dev,
-				"%s: Bad request status (%d): tmf=%p, old_request=%p\n",
-				__func__, old_request->status, tmf, old_request);
-		break;
-
-	case isci_tmf_timed_out:
-
-		/* Set the task's state to "aborting", since the abort task
-		 * function thread set it to "aborted" (above) in anticipation
-		 * of the task management request working correctly.  Since the
-		 * timeout has now fired, the TMF request failed.  We set the
-		 * state such that the request completion will indicate the
-		 * device is no longer present.
-		 */
-		isci_request_change_state(old_request, aborting);
-		break;
-
-	default:
-		dev_dbg(&old_request->isci_host->pdev->dev,
-			"%s: Bad cb_state (%d): tmf=%p, old_request=%p\n",
-			__func__, cb_state, tmf, old_request);
-		break;
-	}
-}
-
-/**
  * isci_task_abort_task() - This function is one of the SAS Domain Template
  *    functions. This function is called by libsas to abort a specified task.
  * @task: This parameter specifies the SAS task to abort.
@@ -956,22 +485,20 @@ static void isci_abort_task_process_cb(
  */
 int isci_task_abort_task(struct sas_task *task)
 {
-	struct isci_host *isci_host = dev_to_ihost(task->dev);
+	struct isci_host *ihost = dev_to_ihost(task->dev);
 	DECLARE_COMPLETION_ONSTACK(aborted_io_completion);
 	struct isci_request       *old_request = NULL;
-	enum isci_request_status  old_state;
-	struct isci_remote_device *isci_device = NULL;
+	struct isci_remote_device *idev = NULL;
 	struct isci_tmf           tmf;
 	int                       ret = TMF_RESP_FUNC_FAILED;
 	unsigned long             flags;
-	int                       perform_termination = 0;
 
 	/* Get the isci_request reference from the task.  Note that
 	 * this check does not depend on the pending request list
 	 * in the device, because tasks driving resets may land here
 	 * after completion in the core.
 	 */
-	spin_lock_irqsave(&isci_host->scic_lock, flags);
+	spin_lock_irqsave(&ihost->scic_lock, flags);
 	spin_lock(&task->task_state_lock);
 
 	old_request = task->lldd_task;
@@ -980,20 +507,20 @@ int isci_task_abort_task(struct sas_task *task)
 	if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
 	    (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
 	    old_request)
-		isci_device = isci_lookup_device(task->dev);
+		idev = isci_lookup_device(task->dev);
 
 	spin_unlock(&task->task_state_lock);
-	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-	dev_warn(&isci_host->pdev->dev,
-		"%s: dev = %p, task = %p, old_request == %p\n",
-		__func__, isci_device, task, old_request);
+	dev_warn(&ihost->pdev->dev,
+		 "%s: dev = %p, task = %p, old_request == %p\n",
+		 __func__, idev, task, old_request);
 
 	/* Device reset conditions signalled in task_state_flags are the
 	 * responsbility of libsas to observe at the start of the error
 	 * handler thread.
 	 */
-	if (!isci_device || !old_request) {
+	if (!idev || !old_request) {
 		/* The request has already completed and there
 		* is nothing to do here other than to set the task
 		* done bit, and indicate that the task abort function
@@ -1007,126 +534,66 @@ int isci_task_abort_task(struct sas_task *task)
 
 		ret = TMF_RESP_FUNC_COMPLETE;
 
-		dev_warn(&isci_host->pdev->dev,
-			"%s: abort task not needed for %p\n",
-			__func__, task);
+		dev_warn(&ihost->pdev->dev,
+			 "%s: abort task not needed for %p\n",
+			 __func__, task);
 		goto out;
 	}
-
-	spin_lock_irqsave(&isci_host->scic_lock, flags);
-
-	/* Check the request status and change to "aborted" if currently
-	 * "starting"; if true then set the I/O kernel completion
-	 * struct that will be triggered when the request completes.
-	 */
-	old_state = isci_task_validate_request_to_abort(
-				old_request, isci_host, isci_device,
-				&aborted_io_completion);
-	if ((old_state != started) &&
-	    (old_state != completed) &&
-	    (old_state != aborting)) {
-
-		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
-
-		/* The request was already being handled by someone else (because
-		* they got to set the state away from started).
-		*/
-		dev_warn(&isci_host->pdev->dev,
-			"%s:  device = %p; old_request %p already being aborted\n",
-			__func__,
-			isci_device, old_request);
-		ret = TMF_RESP_FUNC_COMPLETE;
+	/* Suspend the RNC, kill the TC */
+	if (isci_remote_device_suspend_terminate(ihost, idev, old_request)
+	    != SCI_SUCCESS) {
+		dev_warn(&ihost->pdev->dev,
+			 "%s: isci_remote_device_reset_terminate(dev=%p, "
+				 "req=%p, task=%p) failed\n",
+			 __func__, idev, old_request, task);
+		ret = TMF_RESP_FUNC_FAILED;
 		goto out;
 	}
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+
 	if (task->task_proto == SAS_PROTOCOL_SMP ||
 	    sas_protocol_ata(task->task_proto) ||
 	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
 
-		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+		/* No task to send, so explicitly resume the device here */
+		sci_remote_device_resume(idev, NULL, NULL);
 
-		dev_warn(&isci_host->pdev->dev,
-			"%s: %s request"
-			" or complete_in_target (%d), thus no TMF\n",
-			__func__,
-			((task->task_proto == SAS_PROTOCOL_SMP)
-				? "SMP"
-				: (sas_protocol_ata(task->task_proto)
-					? "SATA/STP"
-					: "<other>")
-			 ),
-			test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags));
-
-		if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
-			spin_lock_irqsave(&task->task_state_lock, flags);
-			task->task_state_flags |= SAS_TASK_STATE_DONE;
-			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
-						    SAS_TASK_STATE_PENDING);
-			spin_unlock_irqrestore(&task->task_state_lock, flags);
-			ret = TMF_RESP_FUNC_COMPLETE;
-		} else {
-			spin_lock_irqsave(&task->task_state_lock, flags);
-			task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
-						    SAS_TASK_STATE_PENDING);
-			spin_unlock_irqrestore(&task->task_state_lock, flags);
-		}
+		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-		/* STP and SMP devices are not sent a TMF, but the
-		 * outstanding I/O request is terminated below.  This is
-		 * because SATA/STP and SMP discovery path timeouts directly
-		 * call the abort task interface for cleanup.
-		 */
-		perform_termination = 1;
-
-		if (isci_device && !test_bit(IDEV_GONE, &isci_device->flags) &&
-		    (isci_remote_device_suspend(isci_host, isci_device)
-		     != SCI_SUCCESS)) {
-			dev_warn(&isci_host->pdev->dev,
-				"%s:  device = %p; failed to suspend\n",
-				__func__, isci_device);
-			goto out;
-		}
+		dev_warn(&ihost->pdev->dev,
+			 "%s: %s request"
+				 " or complete_in_target (%d), thus no TMF\n",
+			 __func__,
+			 ((task->task_proto == SAS_PROTOCOL_SMP)
+			  ? "SMP"
+			  : (sas_protocol_ata(task->task_proto)
+				? "SATA/STP"
+				: "<other>")
+			  ),
+			 test_bit(IREQ_COMPLETE_IN_TARGET,
+				  &old_request->flags));
 
+		spin_lock_irqsave(&task->task_state_lock, flags);
+		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
+					    SAS_TASK_STATE_PENDING);
+		task->task_state_flags |= SAS_TASK_STATE_DONE;
+		spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+		ret = TMF_RESP_FUNC_COMPLETE;
 	} else {
 		/* Fill in the tmf stucture */
 		isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
-					       isci_abort_task_process_cb,
 					       old_request);
 
-		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
-
-		if (isci_remote_device_suspend(isci_host, isci_device)
-		    != SCI_SUCCESS) {
-			dev_warn(&isci_host->pdev->dev,
-				"%s:  device = %p; failed to suspend\n",
-				__func__, isci_device);
-			goto out;
-		}
+		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
+		/* Send the task management request. */
 		#define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
-		ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
+		ret = isci_task_execute_tmf(ihost, idev, &tmf,
 					    ISCI_ABORT_TASK_TIMEOUT_MS);
-
-		if (ret == TMF_RESP_FUNC_COMPLETE)
-			perform_termination = 1;
-		else
-			dev_warn(&isci_host->pdev->dev,
-				"%s: isci_task_send_tmf failed\n", __func__);
-	}
-	if (perform_termination) {
-		set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags);
-
-		/* Clean up the request on our side, and wait for the aborted
-		 * I/O to complete.
-		 */
-		isci_terminate_request_core(isci_host, isci_device,
-					    old_request);
-		isci_remote_device_resume(isci_host, isci_device, NULL, NULL);
 	}
-
-	/* Make sure we do not leave a reference to aborted_io_completion */
-	old_request->io_request_completion = NULL;
- out:
-	isci_put_device(isci_device);
+out:
+	isci_put_device(idev);
 	return ret;
 }
 
@@ -1222,14 +689,11 @@ isci_task_request_complete(struct isci_host *ihost,
 {
 	struct isci_tmf *tmf = isci_request_access_tmf(ireq);
 	struct completion *tmf_complete = NULL;
-	struct completion *request_complete = ireq->io_request_completion;
 
 	dev_dbg(&ihost->pdev->dev,
 		"%s: request = %p, status=%d\n",
 		__func__, ireq, completion_status);
 
-	isci_request_change_state(ireq, completed);
-
 	set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags);
 
 	if (tmf) {
@@ -1253,20 +717,8 @@ isci_task_request_complete(struct isci_host *ihost,
 	 */
 	set_bit(IREQ_TERMINATED, &ireq->flags);
 
-	/* As soon as something is in the terminate path, deallocation is
-	 * managed there.  Note that the final non-managed state of a task
-	 * request is "completed".
-	 */
-	if ((ireq->status == completed) ||
-	    !isci_request_is_dealloc_managed(ireq->status)) {
-		isci_request_change_state(ireq, unallocated);
-		isci_free_tag(ihost, ireq->io_tag);
-		list_del_init(&ireq->dev_node);
-	}
-
-	/* "request_complete" is set if the task was being terminated. */
-	if (request_complete)
-		complete(request_complete);
+	isci_free_tag(ihost, ireq->io_tag);
+	list_del_init(&ireq->dev_node);
 
 	/* The task management part completes last. */
 	if (tmf_complete)
@@ -1277,37 +729,37 @@ static int isci_reset_device(struct isci_host *ihost,
 			     struct domain_device *dev,
 			     struct isci_remote_device *idev)
 {
-	int rc;
-	enum sci_status status;
+	int rc = TMF_RESP_FUNC_COMPLETE, reset_stat;
 	struct sas_phy *phy = sas_get_local_phy(dev);
 	struct isci_port *iport = dev->port->lldd_port;
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
 
-	if (isci_remote_device_reset(ihost, idev) != SCI_SUCCESS) {
+	/* Suspend the RNC, terminate all outstanding TCs. */
+	if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+	    != SCI_SUCCESS) {
 		rc = TMF_RESP_FUNC_FAILED;
 		goto out;
 	}
+	/* Note that since the termination for outstanding requests succeeded,
+	 * this function will return success.  This is because the resets will
+	 * only fail if the device has been removed (ie. hotplug), and the
+	 * primary duty of this function is to cleanup tasks, so that is the
+	 * relevant status.
+	 */
 
 	if (scsi_is_sas_phy_local(phy)) {
 		struct isci_phy *iphy = &ihost->phys[phy->number];
 
-		rc = isci_port_perform_hard_reset(ihost, iport, iphy);
+		reset_stat = isci_port_perform_hard_reset(ihost, iport, iphy);
 	} else
-		rc = sas_phy_reset(phy, !dev_is_sata(dev));
+		reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
 
-	/* Terminate in-progress I/O now. */
-	isci_remote_device_nuke_requests(ihost, idev);
-
-	/* Since all pending TCs have been cleaned, resume the RNC. */
-	status = isci_remote_device_reset_complete(ihost, idev);
-
-	if (status != SCI_SUCCESS)
-		dev_dbg(&ihost->pdev->dev,
-			 "%s: isci_remote_device_reset_complete(%p) "
-			 "returned %d!\n", __func__, idev, status);
+	/* Explicitly resume the RNC here, since there was no task sent. */
+	isci_remote_device_resume(ihost, idev, NULL, NULL);
 
-	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
+	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete, reset_stat=%d.\n",
+		__func__, idev, reset_stat);
  out:
 	sas_put_local_phy(phy);
 	return rc;
@@ -1321,7 +773,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
 	int ret;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	idev = isci_get_device(dev);
+	idev = isci_get_device(dev->lldd_dev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	if (!idev) {
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h
index 7b6d0e3..9c06cba 100644
--- a/drivers/scsi/isci/task.h
+++ b/drivers/scsi/isci/task.h
@@ -63,19 +63,6 @@
 struct isci_request;
 
 /**
- * enum isci_tmf_cb_state - This enum defines the possible states in which the
- *    TMF callback function is invoked during the TMF execution process.
- *
- *
- */
-enum isci_tmf_cb_state {
-
-	isci_tmf_init_state = 0,
-	isci_tmf_started,
-	isci_tmf_timed_out
-};
-
-/**
  * enum isci_tmf_function_codes - This enum defines the possible preparations
  *    of task management requests.
  *
@@ -87,6 +74,7 @@ enum isci_tmf_function_codes {
 	isci_tmf_ssp_task_abort = TMF_ABORT_TASK,
 	isci_tmf_ssp_lun_reset  = TMF_LU_RESET,
 };
+
 /**
  * struct isci_tmf - This class represents the task management object which
  *    acts as an interface to libsas for processing task management requests
@@ -106,15 +94,6 @@ struct isci_tmf {
 	u16 io_tag;
 	enum isci_tmf_function_codes tmf_code;
 	int status;
-
-	/* The optional callback function allows the user process to
-	 * track the TMF transmit / timeout conditions.
-	 */
-	void (*cb_state_func)(
-		enum isci_tmf_cb_state,
-		struct isci_tmf *, void *);
-	void *cb_data;
-
 };
 
 static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf)
@@ -208,113 +187,4 @@ int isci_queuecommand(
 	struct scsi_cmnd *scsi_cmd,
 	void (*donefunc)(struct scsi_cmnd *));
 
-/**
- * enum isci_completion_selection - This enum defines the possible actions to
- *    take with respect to a given request's notification back to libsas.
- *
- *
- */
-enum isci_completion_selection {
-
-	isci_perform_normal_io_completion,      /* Normal notify (task_done) */
-	isci_perform_aborted_io_completion,     /* No notification.   */
-	isci_perform_error_io_completion        /* Use sas_task_abort */
-};
-
-/**
- * isci_task_set_completion_status() - This function sets the completion status
- *    for the request.
- * @task: This parameter is the completed request.
- * @response: This parameter is the response code for the completed task.
- * @status: This parameter is the status code for the completed task.
- *
-* @return The new notification mode for the request.
-*/
-static inline enum isci_completion_selection
-isci_task_set_completion_status(
-	struct sas_task *task,
-	enum service_response response,
-	enum exec_status status,
-	enum isci_completion_selection task_notification_selection)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-
-	/* If a device reset is being indicated, make sure the I/O
-	* is in the error path.
-	*/
-	if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) {
-		/* Fail the I/O to make sure it goes into the error path. */
-		response = SAS_TASK_UNDELIVERED;
-		status = SAM_STAT_TASK_ABORTED;
-
-		task_notification_selection = isci_perform_error_io_completion;
-	}
-	task->task_status.resp = response;
-	task->task_status.stat = status;
-
-	switch (task->task_proto) {
-
-	case SAS_PROTOCOL_SATA:
-	case SAS_PROTOCOL_STP:
-	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
-
-		if (task_notification_selection
-		    == isci_perform_error_io_completion) {
-			/* SATA/STP I/O has it's own means of scheduling device
-			* error handling on the normal path.
-			*/
-			task_notification_selection
-				= isci_perform_normal_io_completion;
-		}
-		break;
-	default:
-		break;
-	}
-
-	switch (task_notification_selection) {
-
-	case isci_perform_error_io_completion:
-
-		if (task->task_proto == SAS_PROTOCOL_SMP) {
-			/* There is no error escalation in the SMP case.
-			 * Convert to a normal completion to avoid the
-			 * timeout in the discovery path and to let the
-			 * next action take place quickly.
-			 */
-			task_notification_selection
-				= isci_perform_normal_io_completion;
-
-			/* Fall through to the normal case... */
-		} else {
-			/* Use sas_task_abort */
-			/* Leave SAS_TASK_STATE_DONE clear
-			 * Leave SAS_TASK_AT_INITIATOR set.
-			 */
-			break;
-		}
-
-	case isci_perform_aborted_io_completion:
-		/* This path can occur with task-managed requests as well as
-		 * requests terminated because of LUN or device resets.
-		 */
-		/* Fall through to the normal case... */
-	case isci_perform_normal_io_completion:
-		/* Normal notification (task_done) */
-		task->task_state_flags |= SAS_TASK_STATE_DONE;
-		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
-					    SAS_TASK_STATE_PENDING);
-		break;
-	default:
-		WARN_ONCE(1, "unknown task_notification_selection: %d\n",
-			 task_notification_selection);
-		break;
-	}
-
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	return task_notification_selection;
-
-}
 #endif /* !defined(_SCI_TASK_H_) */


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 10/37] isci: Add suspension cases for RNC INVALIDATING, POSTING states.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (8 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 09/37] isci: Redesign device suspension, abort, cleanup Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 11/37] isci: Device access in the error path does not depend on IDEV_GONE Dan Williams
                   ` (26 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

The RNC can be any of the states in the loop from suspended to
ready when the API "suspend" or "resume" are called.  This change
adds destination states parameters that control the suspension /
resumption action of the RNC statemachine for those transition states.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/port.c                |   11 --
 drivers/scsi/isci/remote_device.c       |    2 
 drivers/scsi/isci/remote_node_context.c |  145 +++++++++++++++++++++----------
 drivers/scsi/isci/remote_node_context.h |   10 +-
 4 files changed, 105 insertions(+), 63 deletions(-)

diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 00666f7..4858ddd 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -1686,17 +1686,6 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor
 			__func__, iport, status);
 
 	}
-
-	/* If the hard reset for the port has failed, consider this
-	 * the same as link failures on all phys in the port.
-	 */
-	if (ret != TMF_RESP_FUNC_COMPLETE) {
-
-		dev_err(&ihost->pdev->dev,
-			"%s: iport = %p; hard reset failed "
-			"(0x%x) - driving explicit link fail for all phys\n",
-			__func__, iport, iport->hard_reset_status);
-	}
 	return ret;
 }
 
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index c47304c..cf5d554 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -192,7 +192,7 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
 					 u32 reason)
 {
 	dev_dbg(&ihost->pdev->dev,
-		"%s: isci_device = %p\n", __func__, idev);
+		"%s: isci_device = %p; reason = %d\n", __func__, idev, reason);
 
 	switch (reason) {
 	case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index feeca17..75cf043 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -165,21 +165,24 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
 static void sci_remote_node_context_setup_to_resume(
 	struct sci_remote_node_context *sci_rnc,
 	scics_sds_remote_node_context_callback callback,
-	void *callback_parameter)
+	void *callback_parameter,
+	enum sci_remote_node_context_destination_state dest_param)
 {
-	if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) {
-		sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY;
-		sci_rnc->user_callback     = callback;
-		sci_rnc->user_cookie       = callback_parameter;
+	if (sci_rnc->destination_state != RNC_DEST_FINAL) {
+		sci_rnc->destination_state = dest_param;
+		if (callback != NULL) {
+			sci_rnc->user_callback = callback;
+			sci_rnc->user_cookie   = callback_parameter;
+		}
 	}
 }
 
-static void sci_remote_node_context_setup_to_destory(
+static void sci_remote_node_context_setup_to_destroy(
 	struct sci_remote_node_context *sci_rnc,
 	scics_sds_remote_node_context_callback callback,
 	void *callback_parameter)
 {
-	sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL;
+	sci_rnc->destination_state = RNC_DEST_FINAL;
 	sci_rnc->user_callback     = callback;
 	sci_rnc->user_cookie       = callback_parameter;
 }
@@ -203,9 +206,13 @@ static void sci_remote_node_context_notify_user(
 
 static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc)
 {
-	if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY)
+	if ((rnc->destination_state == RNC_DEST_READY) ||
+	    (rnc->destination_state == RNC_DEST_SUSPENDED_RESUME)) {
+		rnc->destination_state = RNC_DEST_READY;
 		sci_remote_node_context_resume(rnc, rnc->user_callback,
 						    rnc->user_cookie);
+	} else
+		rnc->destination_state = RNC_DEST_UNSPECIFIED;
 }
 
 static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc)
@@ -252,7 +259,7 @@ static void sci_remote_node_context_initial_state_enter(struct sci_base_state_ma
 	 * someone requested to destroy the remote node context object.
 	 */
 	if (sm->previous_state_id == SCI_RNC_INVALIDATING) {
-		rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+		rnc->destination_state = RNC_DEST_UNSPECIFIED;
 		sci_remote_node_context_notify_user(rnc);
 	}
 }
@@ -297,10 +304,26 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m
 static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm)
 {
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
-
-	rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
-
-	if (rnc->user_callback)
+	enum sci_remote_node_context_destination_state dest_select;
+	scics_sds_remote_node_context_callback usr_cb = rnc->user_callback;
+	void *usr_param = rnc->user_cookie;
+	int tell_user = 1;
+
+	dest_select = rnc->destination_state;
+	rnc->destination_state = RNC_DEST_UNSPECIFIED;
+
+	if ((dest_select == RNC_DEST_SUSPENDED) ||
+	    (dest_select == RNC_DEST_SUSPENDED_RESUME)) {
+		sci_remote_node_context_suspend(
+			rnc, SCI_SOFTWARE_SUSPENSION,
+			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
+
+		if (dest_select == RNC_DEST_SUSPENDED_RESUME) {
+			sci_remote_node_context_resume(rnc, usr_cb, usr_param);
+			tell_user = 0;  /* Wait until ready again. */
+		}
+	}
+	if (tell_user && rnc->user_callback)
 		sci_remote_node_context_notify_user(rnc);
 }
 
@@ -366,7 +389,7 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
 	memset(rnc, 0, sizeof(struct sci_remote_node_context));
 
 	rnc->remote_node_index = remote_node_index;
-	rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+	rnc->destination_state = RNC_DEST_UNSPECIFIED;
 
 	sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL);
 }
@@ -390,11 +413,11 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 		break;
 	case SCI_RNC_INVALIDATING:
 		if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) {
-			if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL)
-				state = SCI_RNC_INITIAL;
+			if (sci_rnc->destination_state == RNC_DEST_FINAL)
+				next_state = SCI_RNC_INITIAL;
 			else
-				state = SCI_RNC_POSTING;
-			sci_change_state(&sci_rnc->sm, state);
+				next_state = SCI_RNC_POSTING;
+			sci_change_state(&sci_rnc->sm, next_state);
 		} else {
 			switch (scu_get_event_type(event_code)) {
 			case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
@@ -483,7 +506,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 	state = sci_rnc->sm.current_state_id;
 	switch (state) {
 	case SCI_RNC_INVALIDATING:
-		sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p);
+		sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
 		return SCI_SUCCESS;
 	case SCI_RNC_POSTING:
 	case SCI_RNC_RESUMING:
@@ -491,7 +514,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 	case SCI_RNC_TX_SUSPENDED:
 	case SCI_RNC_TX_RX_SUSPENDED:
 	case SCI_RNC_AWAIT_SUSPENSION:
-		sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p);
+		sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
 		sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
 		return SCI_SUCCESS;
 	case SCI_RNC_INITIAL:
@@ -522,6 +545,8 @@ enum sci_status sci_remote_node_context_suspend(
 		= sci_rnc->sm.current_state_id;
 	struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
 	enum sci_status status = SCI_FAILURE_INVALID_STATE;
+	enum sci_remote_node_context_destination_state dest_param =
+		RNC_DEST_UNSPECIFIED;
 
 	dev_dbg(scirdev_to_dev(idev),
 		"%s: current state %d, current suspend_type %x dest state %d,"
@@ -531,12 +556,31 @@ enum sci_status sci_remote_node_context_suspend(
 		suspend_type);
 
 	/* Disable automatic state continuations if explicitly suspending. */
-	if (suspend_reason == SCI_SOFTWARE_SUSPENSION)
-		sci_rnc->destination_state
-			= SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED;
+	if ((suspend_reason != SCI_SOFTWARE_SUSPENSION) ||
+	    (sci_rnc->destination_state == RNC_DEST_FINAL))
+		dest_param = sci_rnc->destination_state;
+
 	switch (state) {
+	case SCI_RNC_RESUMING:
+		break;  /* The RNC has been posted, so start the suspend. */
 	case SCI_RNC_READY:
 		break;
+	case SCI_RNC_INVALIDATING:
+		if (sci_rnc->destination_state == RNC_DEST_FINAL) {
+			dev_warn(scirdev_to_dev(idev),
+				 "%s: already destroying %p\n",
+				 __func__, sci_rnc);
+			return SCI_FAILURE_INVALID_STATE;
+		}
+		/* Fall through and handle like SCI_RNC_POSTING */
+	case SCI_RNC_POSTING:
+		/* Set the destination state to AWAIT - this signals the
+		 * entry into the SCI_RNC_READY state that a suspension
+		 * needs to be done immediately.
+		 */
+		sci_rnc->destination_state = RNC_DEST_SUSPENDED;
+		return SCI_SUCCESS;
+
 	case SCI_RNC_TX_SUSPENDED:
 		if (suspend_type == SCU_EVENT_TL_RNC_SUSPEND_TX)
 			status = SCI_SUCCESS;
@@ -556,6 +600,7 @@ enum sci_status sci_remote_node_context_suspend(
 			 rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
+	sci_rnc->destination_state = dest_param;
 	sci_rnc->user_callback = cb_fn;
 	sci_rnc->user_cookie   = cb_p;
 	sci_rnc->suspend_type  = suspend_type;
@@ -590,18 +635,31 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 		if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
 			return SCI_FAILURE_INVALID_STATE;
 
-		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
+							RNC_DEST_READY);
 		sci_remote_node_context_construct_buffer(sci_rnc);
 		sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
 		return SCI_SUCCESS;
 	case SCI_RNC_POSTING:
 	case SCI_RNC_INVALIDATING:
 	case SCI_RNC_RESUMING:
-		if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY)
-			return SCI_FAILURE_INVALID_STATE;
-
-		sci_rnc->user_callback = cb_fn;
-		sci_rnc->user_cookie   = cb_p;
+		/* We are still waiting to post when a resume was requested. */
+		switch (sci_rnc->destination_state) {
+		case RNC_DEST_SUSPENDED:
+		case RNC_DEST_SUSPENDED_RESUME:
+			/* Previously waiting to suspend after posting.  Now
+			 * continue onto resumption.
+			 */
+			sci_remote_node_context_setup_to_resume(
+				sci_rnc, cb_fn, cb_p,
+				RNC_DEST_SUSPENDED_RESUME);
+			break;
+		default:
+			sci_remote_node_context_setup_to_resume(
+				sci_rnc, cb_fn, cb_p,
+				RNC_DEST_READY);
+			break;
+		}
 		return SCI_SUCCESS;
 	case SCI_RNC_TX_SUSPENDED:
 	case SCI_RNC_TX_RX_SUSPENDED: {
@@ -613,7 +671,8 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 		 * to clear the TCi to NCQ tag mapping table for the RNi.
 		 * All other device types we can just resume.
 		 */
-		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
+							RNC_DEST_READY);
 
 		if (dev_is_sata(dev) && dev->parent)
 			sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
@@ -622,7 +681,9 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 		return SCI_SUCCESS;
 	}
 	case SCI_RNC_AWAIT_SUSPENSION:
-		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p);
+		sci_remote_node_context_setup_to_resume(
+			sci_rnc, cb_fn, cb_p,
+			RNC_DEST_SUSPENDED_RESUME);
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
@@ -663,24 +724,12 @@ enum sci_status sci_remote_node_context_start_task(
 	scics_sds_remote_node_context_callback cb_fn,
 	void *cb_p)
 {
-	enum scis_sds_remote_node_context_states state;
-
-	state = sci_rnc->sm.current_state_id;
-	switch (state) {
-	case SCI_RNC_RESUMING:
-	case SCI_RNC_READY:
-	case SCI_RNC_AWAIT_SUSPENSION:
-		return SCI_SUCCESS;
-	case SCI_RNC_TX_SUSPENDED:
-	case SCI_RNC_TX_RX_SUSPENDED:
-		sci_remote_node_context_resume(sci_rnc, cb_fn, cb_p);
-		return SCI_SUCCESS;
-	default:
+	enum sci_status status = sci_remote_node_context_resume(sci_rnc,
+								cb_fn, cb_p);
+	if (status != SCI_SUCCESS)
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			"%s: invalid state %s\n", __func__,
-			rnc_state_name(state));
-		return SCI_FAILURE_INVALID_STATE;
-	}
+			"%s: resume failed: %d\n", __func__, status);
+	return status;
 }
 
 int sci_remote_node_context_is_safe_to_abort(
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 2870af1..4831906 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -141,9 +141,13 @@ const char *rnc_state_name(enum scis_sds_remote_node_context_states state);
  * node context.
  */
 enum sci_remote_node_context_destination_state {
-	SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED,
-	SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY,
-	SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL
+	RNC_DEST_UNSPECIFIED,
+	RNC_DEST_READY,
+	RNC_DEST_FINAL,
+	RNC_DEST_SUSPENDED,       /* Set when suspend during post/invalidate */
+	RNC_DEST_SUSPENDED_RESUME /* Set when a resume was done during posting
+				   * or invalidating and already suspending.
+				   */
 };
 
 /**


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 11/37] isci: Device access in the error path does not depend on IDEV_GONE.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (9 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 10/37] isci: Add suspension cases for RNC INVALIDATING, POSTING states Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:28 ` [isci-rnc PATCH v1 12/37] isci: All pending TCs are terminated when the RNC is invalidated Dan Williams
                   ` (25 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/task.c |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 29ce881..9d8720d 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -427,7 +427,7 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 	int ret;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	idev = isci_lookup_device(dev);
+	idev = isci_get_device(dev->lldd_dev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	dev_dbg(&ihost->pdev->dev,
@@ -507,7 +507,7 @@ int isci_task_abort_task(struct sas_task *task)
 	if (!(task->task_state_flags & SAS_TASK_STATE_DONE) &&
 	    (task->task_state_flags & SAS_TASK_AT_INITIATOR) &&
 	    old_request)
-		idev = isci_lookup_device(task->dev);
+		idev = isci_get_device(task->dev->lldd_dev);
 
 	spin_unlock(&task->task_state_lock);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -593,6 +593,9 @@ int isci_task_abort_task(struct sas_task *task)
 					    ISCI_ABORT_TASK_TIMEOUT_MS);
 	}
 out:
+	dev_warn(&ihost->pdev->dev,
+		 "%s: Done; dev = %p, task = %p , old_request == %p\n",
+		 __func__, idev, task, old_request);
 	isci_put_device(idev);
 	return ret;
 }


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 12/37] isci: All pending TCs are terminated when the RNC is invalidated.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (10 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 11/37] isci: Device access in the error path does not depend on IDEV_GONE Dan Williams
@ 2012-03-23  0:28 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 13/37] isci: Only set IDEV_GONE in the device stop path Dan Williams
                   ` (24 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_node_context.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 75cf043..adbb4b8 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -275,8 +275,8 @@ static void sci_remote_node_context_invalidating_state_enter(struct sci_base_sta
 {
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
 
-	/* Terminate outstanding requests pending abort. */
-	sci_remote_device_abort_requests_pending_abort(rnc_to_dev(rnc));
+	/* Terminate all outstanding requests. */
+	sci_remote_device_terminate_requests(rnc_to_dev(rnc));
 	sci_remote_node_context_invalidate_context_buffer(rnc);
 }
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 13/37] isci: Only set IDEV_GONE in the device stop path.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (11 preceding siblings ...)
  2012-03-23  0:28 ` [isci-rnc PATCH v1 12/37] isci: All pending TCs are terminated when the RNC is invalidated Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 14/37] isci: Remove isci_device reqs_in_process and dev_node from isci_device Dan Williams
                   ` (23 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/port.c          |   23 -----------------------
 drivers/scsi/isci/remote_device.c |    3 ---
 2 files changed, 0 insertions(+), 26 deletions(-)

diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 4858ddd..87944c8 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -240,32 +240,9 @@ static void isci_port_link_down(struct isci_host *isci_host,
 				struct isci_phy *isci_phy,
 				struct isci_port *isci_port)
 {
-	struct isci_remote_device *isci_device;
-
 	dev_dbg(&isci_host->pdev->dev,
 		"%s: isci_port = %p\n", __func__, isci_port);
 
-	if (isci_port) {
-
-		/* check to see if this is the last phy on this port. */
-		if (isci_phy->sas_phy.port &&
-		    isci_phy->sas_phy.port->num_phys == 1) {
-			/* change the state for all devices on this port.  The
-			 * next task sent to this device will be returned as
-			 * SAS_TASK_UNDELIVERED, and the scsi mid layer will
-			 * remove the target
-			 */
-			list_for_each_entry(isci_device,
-					    &isci_port->remote_dev_list,
-					    node) {
-				dev_dbg(&isci_host->pdev->dev,
-					"%s: isci_device = %p\n",
-					__func__, isci_device);
-				set_bit(IDEV_GONE, &isci_device->flags);
-			}
-		}
-	}
-
 	/* Notify libsas of the borken link, this will trigger calls to our
 	 * isci_port_deformed and isci_dev_gone functions.
 	 */
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index cf5d554..b26ab05 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -195,9 +195,6 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
 		"%s: isci_device = %p; reason = %d\n", __func__, idev, reason);
 
 	switch (reason) {
-	case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED:
-		set_bit(IDEV_GONE, &idev->flags);
-		break;
 	case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED:
 		set_bit(IDEV_IO_NCQERROR, &idev->flags);
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 14/37] isci: Remove isci_device reqs_in_process and dev_node from isci_device.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (12 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 13/37] isci: Only set IDEV_GONE in the device stop path Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 15/37] isci: Distinguish between remote device suspension cases Dan Williams
                   ` (22 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/init.c          |    1 -
 drivers/scsi/isci/remote_device.c |    6 +-----
 drivers/scsi/isci/remote_device.h |    1 -
 drivers/scsi/isci/request.c       |   12 ------------
 drivers/scsi/isci/request.h       |    2 --
 drivers/scsi/isci/task.c          |    4 ----
 6 files changed, 1 insertions(+), 25 deletions(-)

diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 6fc72d8..2a781c2 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -573,7 +573,6 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
 	for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) {
 		struct isci_remote_device *idev = &ihost->devices[i];
 
-		INIT_LIST_HEAD(&idev->reqs_in_process);
 		INIT_LIST_HEAD(&idev->node);
 	}
 
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index b26ab05..b14eff3 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -919,7 +919,7 @@ static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_
 	 * here should go through isci_remote_device_nuke_requests.
 	 * If we hit this condition, we will need a way to complete
 	 * io requests in process */
-	BUG_ON(!list_empty(&idev->reqs_in_process));
+	BUG_ON(idev->started_request_count > 0);
 
 	sci_remote_device_destruct(idev);
 	list_del_init(&idev->node);
@@ -1345,10 +1345,6 @@ isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport)
 		dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__);
 		return NULL;
 	}
-
-	if (WARN_ONCE(!list_empty(&idev->reqs_in_process), "found requests in process\n"))
-		return NULL;
-
 	if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n"))
 		return NULL;
 
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index da43698..8b7817c 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -90,7 +90,6 @@ struct isci_remote_device {
 	struct isci_port *isci_port;
 	struct domain_device *domain_dev;
 	struct list_head node;
-	struct list_head reqs_in_process;
 	struct sci_base_state_machine sm;
 	u32 device_port_width;
 	enum sas_linkrate connection_rate;
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 2d27ebd..c6a522c 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2956,9 +2956,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 	/* Add to the completed list. */
 	list_add(&request->completed_node, &ihost->requests_to_complete);
 
-	/* Take the request off the device's pending request list. */
-	list_del_init(&request->dev_node);
-
 	/* complete the io request to the core. */
 	sci_controller_complete_io(ihost, request->target_device, request);
 
@@ -3412,7 +3409,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t
 	ireq->flags = 0;
 	ireq->num_sg_entries = 0;
 	INIT_LIST_HEAD(&ireq->completed_node);
-	INIT_LIST_HEAD(&ireq->dev_node);
 
 	return ireq;
 }
@@ -3496,17 +3492,9 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		return status;
 	}
-
 	/* Either I/O started OK, or the core has signaled that
 	 * the device needs a target reset.
-	 *
-	 * In either case, hold onto the I/O for later.
-	 *
-	 * Update it's status and add it to the list in the
-	 * remote device object.
 	 */
-	list_add(&ireq->dev_node, &idev->reqs_in_process);
-
 	if (status != SCI_SUCCESS) {
 		/* The request did not really start in the
 		 * hardware, so clear the request handle
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index f3116a5..d12e975 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -96,8 +96,6 @@ struct isci_request {
 	struct isci_host *isci_host;
 	/* For use in the requests_to_{complete|abort} lists: */
 	struct list_head completed_node;
-	/* For use in the reqs_in_process list: */
-	struct list_head dev_node;
 	dma_addr_t request_daddr;
 	dma_addr_t zero_scatter_daddr;
 	unsigned int num_sg_entries;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 9d8720d..222fb0d 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -317,9 +317,6 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		goto err_tci;
 	}
-	/* add the request to the remote device request list. */
-	list_add(&ireq->dev_node, &idev->reqs_in_process);
-
 	/* The RNC must be unsuspended before the TMF can get a response. */
 	sci_remote_device_resume(idev, NULL, NULL);
 
@@ -721,7 +718,6 @@ isci_task_request_complete(struct isci_host *ihost,
 	set_bit(IREQ_TERMINATED, &ireq->flags);
 
 	isci_free_tag(ihost, ireq->io_tag);
-	list_del_init(&ireq->dev_node);
 
 	/* The task management part completes last. */
 	if (tmf_complete)


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 15/37] isci: Distinguish between remote device suspension cases
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (13 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 14/37] isci: Remove isci_device reqs_in_process and dev_node from isci_device Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 16/37] isci: Fix the terminated I/O to not call sas_task_abort() Dan Williams
                   ` (21 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

For NCQ error conditions among others, there is no need to enable
the link layer hang detect timer.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |   27 +++++++++++----------------
 drivers/scsi/isci/remote_node_context.c |   19 +++++++++++++------
 drivers/scsi/isci/remote_node_context.h |    5 +++--
 drivers/scsi/isci/request.c             |    2 +-
 4 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index b14eff3..cc8ab69 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -72,10 +72,11 @@ const char *dev_state_name(enum sci_remote_device_states state)
 }
 #undef C
 
-static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev)
+static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+						 enum sci_remote_node_suspension_reasons reason)
 {
 	return sci_remote_node_context_suspend(&idev->rnc,
-					       SCI_SOFTWARE_SUSPENSION,
+					       reason,
 					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
 					       NULL, NULL);
 }
@@ -199,7 +200,7 @@ static void isci_remote_device_not_ready(struct isci_host *ihost,
 		set_bit(IDEV_IO_NCQERROR, &idev->flags);
 
 		/* Suspend the remote device so the I/O can be terminated. */
-		sci_remote_device_suspend(idev);
+		sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL);
 
 		/* Kill all outstanding requests for the device. */
 		sci_remote_device_terminate_requests(idev);
@@ -268,7 +269,8 @@ enum sci_status sci_remote_device_stop(struct isci_remote_device *idev,
 							 rnc_destruct_done,
 							 idev);
 		else {
-			sci_remote_device_suspend(idev);
+			sci_remote_device_suspend(
+				idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
 			sci_remote_device_terminate_requests(idev);
 		}
 		return SCI_SUCCESS;
@@ -473,11 +475,7 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 			status = SCI_SUCCESS;
 
 			/* Suspend the associated RNC */
-			sci_remote_node_context_suspend(
-				&idev->rnc,
-				SCI_SOFTWARE_SUSPENSION,
-				SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
-				NULL, NULL);
+			sci_remote_device_suspend(idev, SCI_SW_SUSPEND_NORMAL);
 
 			dev_dbg(scirdev_to_dev(idev),
 				"%s: device: %p event code: %x: %s\n",
@@ -789,9 +787,8 @@ enum sci_status sci_remote_device_start_task(struct isci_host *ihost,
 		 * the correct action when the remote node context is suspended
 		 * and later resumed.
 		 */
-		sci_remote_node_context_suspend(
-			&idev->rnc, SCI_SOFTWARE_SUSPENSION,
-			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
+		sci_remote_device_suspend(idev,
+					  SCI_SW_SUSPEND_LINKHANG_DETECT);
 
 		status = sci_remote_node_context_start_task(&idev->rnc, ireq,
 				sci_remote_device_continue_request, idev);
@@ -986,9 +983,7 @@ static void sci_remote_device_resetting_state_enter(struct sci_base_state_machin
 	dev_dbg(&ihost->pdev->dev,
 		"%s: isci_device = %p\n", __func__, idev);
 
-	sci_remote_node_context_suspend(
-		&idev->rnc, SCI_SOFTWARE_SUSPENSION,
-		SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
+	sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
 }
 
 static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm)
@@ -1486,7 +1481,7 @@ enum sci_status isci_remote_device_suspend_terminate(
 
 	/* Put the device into suspension. */
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	sci_remote_device_suspend(idev);
+	sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	/* Terminate and wait for the completions. */
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index adbb4b8..85bf5ec 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -52,7 +52,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
+#include <scsi/sas_ata.h>
 #include "host.h"
 #include "isci.h"
 #include "remote_device.h"
@@ -315,7 +315,7 @@ static void sci_remote_node_context_ready_state_enter(struct sci_base_state_mach
 	if ((dest_select == RNC_DEST_SUSPENDED) ||
 	    (dest_select == RNC_DEST_SUSPENDED_RESUME)) {
 		sci_remote_node_context_suspend(
-			rnc, SCI_SOFTWARE_SUSPENSION,
+			rnc, SCI_SW_SUSPEND_NORMAL,
 			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
 
 		if (dest_select == RNC_DEST_SUSPENDED_RESUME) {
@@ -352,8 +352,10 @@ static void sci_remote_node_context_await_suspend_state_exit(
 {
 	struct sci_remote_node_context *rnc
 		= container_of(sm, typeof(*rnc), sm);
+	struct isci_remote_device *idev = rnc_to_dev(rnc);
 
-	isci_dev_set_hang_detection_timeout(rnc_to_dev(rnc), 0);
+	if (dev_is_sata(idev->domain_dev))
+		isci_dev_set_hang_detection_timeout(idev, 0);
 }
 
 static const struct sci_base_state sci_remote_node_context_state_table[] = {
@@ -556,7 +558,7 @@ enum sci_status sci_remote_node_context_suspend(
 		suspend_type);
 
 	/* Disable automatic state continuations if explicitly suspending. */
-	if ((suspend_reason != SCI_SOFTWARE_SUSPENSION) ||
+	if ((suspend_reason == SCI_HW_SUSPEND) ||
 	    (sci_rnc->destination_state == RNC_DEST_FINAL))
 		dest_param = sci_rnc->destination_state;
 
@@ -612,8 +614,13 @@ enum sci_status sci_remote_node_context_suspend(
 		wake_up_all(&ihost->eventq); /* Let observers look. */
 		return SCI_SUCCESS;
 	}
-	if (suspend_reason == SCI_SOFTWARE_SUSPENSION) {
-		isci_dev_set_hang_detection_timeout(idev, 0x00000001);
+	if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) ||
+	    (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) {
+
+		if ((suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)
+		 && dev_is_sata(idev->domain_dev))
+			isci_dev_set_hang_detection_timeout(idev, 0x00000001);
+
 		sci_remote_device_post_request(
 			idev, SCI_SOFTWARE_SUSPEND_CMD);
 	}
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 4831906..364da37 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -76,8 +76,9 @@
 #define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX    0x0FFF
 
 enum sci_remote_node_suspension_reasons {
-	SCU_HARDWARE_SUSPENSION,
-	SCI_SOFTWARE_SUSPENSION
+	SCI_HW_SUSPEND,
+	SCI_SW_SUSPEND_NORMAL,
+	SCI_SW_SUSPEND_LINKHANG_DETECT
 };
 #define SCI_SOFTWARE_SUSPEND_CMD SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX
 #define SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT SCU_EVENT_TL_RNC_SUSPEND_TX_RX
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index c6a522c..d240f6d 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2380,7 +2380,7 @@ static void sci_request_handle_suspending_completions(
 
 		sci_remote_node_context_suspend(
 			&ireq->target_device->rnc,
-			SCU_HARDWARE_SUSPENSION,
+			SCI_HW_SUSPEND,
 			(is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX
 				   : SCU_EVENT_TL_RNC_SUSPEND_TX,
 			NULL, NULL);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 16/37] isci: Fix the terminated I/O to not call sas_task_abort().
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (14 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 15/37] isci: Distinguish between remote device suspension cases Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 17/37] isci: Save the suspension hint for upcoming suspensions Dan Williams
                   ` (20 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

This addresses a regression from the commit "isci: Redesign
device suspension, abort, cleanup." in which the sas_task end
condition for terminated I/Os was made to call back on
sas_task_abort()".
This commit will be rolled into the original.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/request.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index d240f6d..78ca516 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2832,7 +2832,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 			__func__, request, task);
 
 		/* The request was terminated explicitly. */
-		clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
+		set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags);
 		response = SAS_TASK_UNDELIVERED;
 
 		/* See if the device has been/is being stopped. Note


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 17/37] isci: Save the suspension hint for upcoming suspensions.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (15 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 16/37] isci: Fix the terminated I/O to not call sas_task_abort() Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 18/37] isci: Manage the LLHANG timer enable/disable per-device Dan Williams
                   ` (19 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

In the case of a suspend call while in SCI_RNC_POSTING or INVALIDATING
states, the LLHANG detect needed to be saved so the upcoming suspension
would enable it correctly.  The unused suspend callback parameters were
removed.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |    6 ++----
 drivers/scsi/isci/remote_node_context.c |   16 +++++++---------
 drivers/scsi/isci/remote_node_context.h |    5 ++---
 drivers/scsi/isci/request.c             |    3 +--
 4 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index cc8ab69..1a85e9e 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -75,10 +75,8 @@ const char *dev_state_name(enum sci_remote_device_states state)
 static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
 						 enum sci_remote_node_suspension_reasons reason)
 {
-	return sci_remote_node_context_suspend(&idev->rnc,
-					       reason,
-					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT,
-					       NULL, NULL);
+	return sci_remote_node_context_suspend(&idev->rnc, reason,
+					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
 }
 
 /**
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 85bf5ec..2ac9260 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -315,8 +315,8 @@ static void sci_remote_node_context_ready_state_enter(struct sci_base_state_mach
 	if ((dest_select == RNC_DEST_SUSPENDED) ||
 	    (dest_select == RNC_DEST_SUSPENDED_RESUME)) {
 		sci_remote_node_context_suspend(
-			rnc, SCI_SW_SUSPEND_NORMAL,
-			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT, NULL, NULL);
+			rnc, rnc->suspend_reason,
+			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
 
 		if (dest_select == RNC_DEST_SUSPENDED_RESUME) {
 			sci_remote_node_context_resume(rnc, usr_cb, usr_param);
@@ -539,9 +539,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 enum sci_status sci_remote_node_context_suspend(
 			struct sci_remote_node_context *sci_rnc,
 			enum sci_remote_node_suspension_reasons suspend_reason,
-			u32 suspend_type,
-			scics_sds_remote_node_context_callback cb_fn,
-			void *cb_p)
+			u32 suspend_type)
 {
 	enum scis_sds_remote_node_context_states state
 		= sci_rnc->sm.current_state_id;
@@ -581,6 +579,8 @@ enum sci_status sci_remote_node_context_suspend(
 		 * needs to be done immediately.
 		 */
 		sci_rnc->destination_state = RNC_DEST_SUSPENDED;
+		sci_rnc->suspend_type = suspend_type;
+		sci_rnc->suspend_reason = suspend_reason;
 		return SCI_SUCCESS;
 
 	case SCI_RNC_TX_SUSPENDED:
@@ -603,14 +603,12 @@ enum sci_status sci_remote_node_context_suspend(
 		return SCI_FAILURE_INVALID_STATE;
 	}
 	sci_rnc->destination_state = dest_param;
-	sci_rnc->user_callback = cb_fn;
-	sci_rnc->user_cookie   = cb_p;
-	sci_rnc->suspend_type  = suspend_type;
+	sci_rnc->suspend_type = suspend_type;
+	sci_rnc->suspend_reason = suspend_reason;
 
 	if (status == SCI_SUCCESS) { /* Already in the destination state? */
 		struct isci_host *ihost = idev->owning_port->owning_controller;
 
-		sci_remote_node_context_notify_user(sci_rnc);
 		wake_up_all(&ihost->eventq); /* Let observers look. */
 		return SCI_SUCCESS;
 	}
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 364da37..9eee304 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -169,6 +169,7 @@ struct sci_remote_node_context {
 	 * context suspension.
 	 */
 	u32 suspend_type;
+	enum sci_remote_node_suspension_reasons suspend_reason;
 
 	/**
 	 * This field is true if the remote node context is resuming from its current
@@ -209,9 +210,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 						      void *callback_parameter);
 enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
 						     u32 suspend_type,
-						     u32 suspension_code,
-						     scics_sds_remote_node_context_callback cb_fn,
-						     void *cb_p);
+						     u32 suspension_code);
 enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,
 						    scics_sds_remote_node_context_callback cb_fn,
 						    void *cb_p);
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 78ca516..df713d5 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2382,8 +2382,7 @@ static void sci_request_handle_suspending_completions(
 			&ireq->target_device->rnc,
 			SCI_HW_SUSPEND,
 			(is_tx_rx) ? SCU_EVENT_TL_RNC_SUSPEND_TX_RX
-				   : SCU_EVENT_TL_RNC_SUSPEND_TX,
-			NULL, NULL);
+				   : SCU_EVENT_TL_RNC_SUSPEND_TX);
 	}
 }
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 18/37] isci: Manage the LLHANG timer enable/disable per-device.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (16 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 17/37] isci: Save the suspension hint for upcoming suspensions Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 19/37] isci: Make sure all TCs are terminated and cleaned in LUN reset Dan Williams
                   ` (18 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

The LLHANG timer should be enabled once per device.  This patch corrects
both the timer enable and the timer disable for the remote device.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |   17 +++++++++++++++++
 drivers/scsi/isci/remote_device.h       |    8 ++------
 drivers/scsi/isci/remote_node_context.c |    3 +--
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 1a85e9e..86aca11 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1520,3 +1520,20 @@ enum sci_status isci_remote_device_reset_complete(
 	return status;
 }
 
+void isci_dev_set_hang_detection_timeout(
+	struct isci_remote_device *idev,
+	u32 timeout)
+{
+	if (dev_is_sata(idev->domain_dev)) {
+		if (timeout) {
+			if (test_and_set_bit(IDEV_RNC_LLHANG_ENABLED,
+					     &idev->flags))
+				return;  /* Already enabled. */
+		} else if (!test_and_clear_bit(IDEV_RNC_LLHANG_ENABLED,
+					       &idev->flags))
+			return;  /* Not enabled. */
+
+		sci_port_set_hang_detection_timeout(idev->owning_port,
+						    timeout);
+	}
+}
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 8b7817c..ef563e5 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -85,6 +85,7 @@ struct isci_remote_device {
 	#define IDEV_GONE 3
 	#define IDEV_IO_READY 4
 	#define IDEV_IO_NCQERROR 5
+	#define IDEV_RNC_LLHANG_ENABLED 6
 	unsigned long flags;
 	struct kref kref;
 	struct isci_port *isci_port;
@@ -308,12 +309,7 @@ static inline void sci_remote_device_decrement_request_count(struct isci_remote_
 		idev->started_request_count--;
 }
 
-static inline void isci_dev_set_hang_detection_timeout(
-	struct isci_remote_device *idev,
-	u32 timeout)
-{
-	sci_port_set_hang_detection_timeout(idev->owning_port, timeout);
-}
+void isci_dev_set_hang_detection_timeout(struct isci_remote_device *idev, u32 timeout);
 
 enum sci_status sci_remote_device_frame_handler(
 	struct isci_remote_device *idev,
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 2ac9260..48565de 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -615,8 +615,7 @@ enum sci_status sci_remote_node_context_suspend(
 	if ((suspend_reason == SCI_SW_SUSPEND_NORMAL) ||
 	    (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)) {
 
-		if ((suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)
-		 && dev_is_sata(idev->domain_dev))
+		if (suspend_reason == SCI_SW_SUSPEND_LINKHANG_DETECT)
 			isci_dev_set_hang_detection_timeout(idev, 0x00000001);
 
 		sci_remote_device_post_request(


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 19/37] isci: Make sure all TCs are terminated and cleaned in LUN reset.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (17 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 18/37] isci: Manage the LLHANG timer enable/disable per-device Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 20/37] isci: Implement waiting for suspend in the abort path Dan Williams
                   ` (17 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

In the libsas error path, SATA disks require extra handling in
libata to recover operation.  However, libsas expects to be able
to immediately recover all outstanding I/O once the error handler
escalation stops.  This patch fixes the condition where the libata
error handler is scheduled for operation but libsas has already
deleted the outstanding sas_tasks.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/task.c |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 222fb0d..5d738fd 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -439,16 +439,18 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 		goto out;
 	}
 
+	/* Suspend the RNC, kill all TCs */
+	if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
+	    != SCI_SUCCESS) {
+		/* The suspend/terminate only fails if isci_get_device fails */
+		ret = TMF_RESP_FUNC_FAILED;
+		goto out;
+	}
+	/* All pending I/Os have been terminated and cleaned up. */
 	if (dev_is_sata(dev)) {
 		sas_ata_schedule_reset(dev);
 		ret = TMF_RESP_FUNC_COMPLETE;
 	} else {
-		/* Suspend the RNC, kill all TCs */
-		if (isci_remote_device_suspend_terminate(ihost, idev, NULL)
-		    != SCI_SUCCESS) {
-			ret = TMF_RESP_FUNC_FAILED;
-			goto out;
-		}
 		/* Send the task management part of the reset. */
 		ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
 	}


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 20/37] isci: Implement waiting for suspend in the abort path.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (18 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 19/37] isci: Make sure all TCs are terminated and cleaned in LUN reset Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 21/37] isci: When in the abort path, defeat other resume calls until done Dan Williams
                   ` (16 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

In order to prevent a device from receiving an I/O request while still
in an RNC suspending or resuming state (and therefore failing that
I/O back to libsas with a reset required status) wait for the RNC state
change before proceding in the abort path.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |   44 +++++++++++++++++++++++--------
 drivers/scsi/isci/remote_device.h       |    6 +---
 drivers/scsi/isci/remote_node_context.c |   21 +++++++++++++++
 drivers/scsi/isci/remote_node_context.h |    3 ++
 drivers/scsi/isci/task.c                |   14 +++++-----
 5 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 86aca11..acc94a4 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -137,6 +137,14 @@ static enum sci_status sci_remote_device_terminate_reqs_checkabort(
 	return status;
 }
 
+static bool isci_compare_suspendcount(
+	struct isci_remote_device *idev,
+	u32 localcount)
+{
+	smp_rmb();
+	return localcount != idev->rnc.suspend_count;
+}
+
 enum sci_status isci_remote_device_terminate_requests(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev,
@@ -144,31 +152,44 @@ enum sci_status isci_remote_device_terminate_requests(
 {
 	enum sci_status status = SCI_SUCCESS;
 	unsigned long flags;
+	u32 rnc_suspend_count;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
+
 	if (isci_get_device(idev) == NULL) {
 		dev_dbg(&ihost->pdev->dev, "%s: failed isci_get_device(idev=%p)\n",
 			__func__, idev);
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		status = SCI_FAILURE;
 	} else {
+		/* If already suspended, don't wait for another suspension. */
+		smp_rmb();
+		rnc_suspend_count
+			= sci_remote_node_context_is_suspended(&idev->rnc)
+				? 0 : idev->rnc.suspend_count;
+
 		dev_dbg(&ihost->pdev->dev,
 			"%s: idev=%p, ireq=%p; started_request_count=%d, "
+				"rnc_suspend_count=%d, rnc.suspend_count=%d"
 				"about to wait\n",
-			__func__, idev, ireq, idev->started_request_count);
+			__func__, idev, ireq, idev->started_request_count,
+			rnc_suspend_count, idev->rnc.suspend_count);
 		if (ireq) {
 			/* Terminate a specific TC. */
 			sci_remote_device_terminate_req(ihost, idev, 0, ireq);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
-			wait_event(ihost->eventq, !test_bit(IREQ_ACTIVE,
-							    &ireq->flags));
-
+			wait_event(ihost->eventq,
+				   (isci_compare_suspendcount(idev,
+							      rnc_suspend_count)
+				    && !test_bit(IREQ_ACTIVE, &ireq->flags)));
 		} else {
 			/* Terminate all TCs. */
 			sci_remote_device_terminate_requests(idev);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
 			wait_event(ihost->eventq,
-				   idev->started_request_count == 0);
+				   (isci_compare_suspendcount(idev,
+							      rnc_suspend_count)
+				    && idev->started_request_count == 0));
 		}
 		dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
 			__func__, idev);
@@ -1234,19 +1255,20 @@ enum sci_status sci_remote_device_resume(
 	return status;
 }
 
-enum sci_status isci_remote_device_resume(
+enum sci_status isci_remote_device_resume_from_abort(
 	struct isci_host *ihost,
-	struct isci_remote_device *idev,
-	scics_sds_remote_node_context_callback cb_fn,
-	void *cb_p)
+	struct isci_remote_device *idev)
 {
 	unsigned long flags;
 	enum sci_status status;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	status = sci_remote_device_resume(idev, cb_fn, cb_p);
+	/* Preserve any current resume callbacks, for instance from other
+	 * resumptions.
+	 */
+	status = sci_remote_device_resume(idev, idev->rnc.user_callback,
+					  idev->rnc.user_cookie);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-
 	return status;
 }
 /**
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index ef563e5..d1d1892 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -357,11 +357,9 @@ enum sci_status sci_remote_device_resume(
 	scics_sds_remote_node_context_callback cb_fn,
 	void *cb_p);
 
-enum sci_status isci_remote_device_resume(
+enum sci_status isci_remote_device_resume_from_abort(
 	struct isci_host *ihost,
-	struct isci_remote_device *idev,
-	scics_sds_remote_node_context_callback cb_fn,
-	void *cb_p);
+	struct isci_remote_device *idev);
 
 enum sci_status isci_remote_device_reset(
 	struct isci_host *ihost,
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 48565de..77c8b51 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -90,6 +90,15 @@ bool sci_remote_node_context_is_ready(
 	return false;
 }
 
+bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc)
+{
+	u32 current_state = sci_rnc->sm.current_state_id;
+
+	if (current_state == SCI_RNC_TX_RX_SUSPENDED)
+		return true;
+	return false;
+}
+
 static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id)
 {
 	if (id < ihost->remote_node_entries &&
@@ -339,6 +348,13 @@ static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
 	struct isci_remote_device *idev = rnc_to_dev(rnc);
 	struct isci_host *ihost = idev->owning_port->owning_controller;
+	u32 new_count = rnc->suspend_count + 1;
+
+	if (new_count == 0)
+		rnc->suspend_count = 1;
+	else
+		rnc->suspend_count = new_count;
+	smp_wmb();
 
 	/* Terminate outstanding requests pending abort. */
 	sci_remote_device_abort_requests_pending_abort(idev);
@@ -634,6 +650,11 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 	enum scis_sds_remote_node_context_states state;
 
 	state = sci_rnc->sm.current_state_id;
+	dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+		 "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d\n",
+		 __func__, rnc_state_name(state), cb_fn, cb_p,
+		 sci_rnc->destination_state);
+
 	switch (state) {
 	case SCI_RNC_INITIAL:
 		if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 9eee304..c61c02e 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -170,6 +170,7 @@ struct sci_remote_node_context {
 	 */
 	u32 suspend_type;
 	enum sci_remote_node_suspension_reasons suspend_reason;
+	u32 suspend_count;
 
 	/**
 	 * This field is true if the remote node context is resuming from its current
@@ -203,6 +204,8 @@ void sci_remote_node_context_construct(struct sci_remote_node_context *rnc,
 bool sci_remote_node_context_is_ready(
 	struct sci_remote_node_context *sci_rnc);
 
+bool sci_remote_node_context_is_suspended(struct sci_remote_node_context *sci_rnc);
+
 enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc,
 							   u32 event_code);
 enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc,
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 5d738fd..c1c6dd0 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -317,11 +317,11 @@ static int isci_task_execute_tmf(struct isci_host *ihost,
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		goto err_tci;
 	}
-	/* The RNC must be unsuspended before the TMF can get a response. */
-	sci_remote_device_resume(idev, NULL, NULL);
-
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
+	/* The RNC must be unsuspended before the TMF can get a response. */
+	isci_remote_device_resume_from_abort(ihost, idev);
+
 	/* Wait for the TMF to complete, or a timeout. */
 	timeleft = wait_for_completion_timeout(&completion,
 					       msecs_to_jiffies(timeout_ms));
@@ -554,11 +554,11 @@ int isci_task_abort_task(struct sas_task *task)
 	    sas_protocol_ata(task->task_proto) ||
 	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
 
-		/* No task to send, so explicitly resume the device here */
-		sci_remote_device_resume(idev, NULL, NULL);
-
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
+		/* No task to send, so explicitly resume the device here */
+		isci_remote_device_resume_from_abort(ihost, idev);
+
 		dev_warn(&ihost->pdev->dev,
 			 "%s: %s request"
 				 " or complete_in_target (%d), thus no TMF\n",
@@ -757,7 +757,7 @@ static int isci_reset_device(struct isci_host *ihost,
 		reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
 
 	/* Explicitly resume the RNC here, since there was no task sent. */
-	isci_remote_device_resume(ihost, idev, NULL, NULL);
+	isci_remote_device_resume_from_abort(ihost, idev);
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete, reset_stat=%d.\n",
 		__func__, idev, reset_stat);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 21/37] isci: When in the abort path, defeat other resume calls until done.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (19 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 20/37] isci: Implement waiting for suspend in the abort path Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 22/37] isci: Callbacks to libsas occur under scic_lock and are synchronized Dan Williams
                   ` (15 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Completion of I/Os during the one of the abort path interface calls
from libsas can drive remote device state changes and the resumption
of the device RNC.  This is a problem when the abort path is
attempting to cleanup outstanding I/O at the same time - the resumption
can prevent the termination from occuring correctly.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |    2 
 drivers/scsi/isci/remote_device.h       |    1 
 drivers/scsi/isci/remote_node_context.c |  126 ++++++++++++++++++++-----------
 3 files changed, 83 insertions(+), 46 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index acc94a4..d1c2a22 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1266,6 +1266,7 @@ enum sci_status isci_remote_device_resume_from_abort(
 	/* Preserve any current resume callbacks, for instance from other
 	 * resumptions.
 	 */
+	clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
 	status = sci_remote_device_resume(idev, idev->rnc.user_callback,
 					  idev->rnc.user_cookie);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
@@ -1501,6 +1502,7 @@ enum sci_status isci_remote_device_suspend_terminate(
 
 	/* Put the device into suspension. */
 	spin_lock_irqsave(&ihost->scic_lock, flags);
+	set_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
 	sci_remote_device_suspend(idev, SCI_SW_SUSPEND_LINKHANG_DETECT);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index d1d1892..53564c3 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -86,6 +86,7 @@ struct isci_remote_device {
 	#define IDEV_IO_READY 4
 	#define IDEV_IO_NCQERROR 5
 	#define IDEV_RNC_LLHANG_ENABLED 6
+	#define IDEV_ABORT_PATH_ACTIVE 7
 	unsigned long flags;
 	struct kref kref;
 	struct isci_port *isci_port;
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 77c8b51..faeae95 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -161,6 +161,14 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
 	rnc->ssp.oaf_more_compatibility_features = 0;
 }
 
+static void sci_remote_node_context_save_cbparams(
+	struct sci_remote_node_context *sci_rnc,
+	scics_sds_remote_node_context_callback callback,
+	void *callback_parameter)
+{
+	sci_rnc->user_callback = callback;
+	sci_rnc->user_cookie   = callback_parameter;
+}
 /**
  *
  * @sci_rnc:
@@ -179,10 +187,9 @@ static void sci_remote_node_context_setup_to_resume(
 {
 	if (sci_rnc->destination_state != RNC_DEST_FINAL) {
 		sci_rnc->destination_state = dest_param;
-		if (callback != NULL) {
-			sci_rnc->user_callback = callback;
-			sci_rnc->user_cookie   = callback_parameter;
-		}
+		if (callback != NULL)
+			sci_remote_node_context_save_cbparams(
+				sci_rnc, callback, callback_parameter);
 	}
 }
 
@@ -648,67 +655,94 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 						    void *cb_p)
 {
 	enum scis_sds_remote_node_context_states state;
+	struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
 
 	state = sci_rnc->sm.current_state_id;
-	dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-		 "%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d\n",
-		 __func__, rnc_state_name(state), cb_fn, cb_p,
-		 sci_rnc->destination_state);
+	dev_dbg(scirdev_to_dev(idev),
+		"%s: state %s, cb_fn = %p, cb_p = %p; dest_state = %d; "
+			"dev resume path %s\n",
+		__func__, rnc_state_name(state), cb_fn, cb_p,
+		sci_rnc->destination_state,
+		test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)
+			? "<abort active>" : "<normal>");
 
 	switch (state) {
 	case SCI_RNC_INITIAL:
 		if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
 			return SCI_FAILURE_INVALID_STATE;
 
-		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
-							RNC_DEST_READY);
-		sci_remote_node_context_construct_buffer(sci_rnc);
-		sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
+		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+							      cb_p);
+		else {
+			sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn,
+							cb_p, RNC_DEST_READY);
+			sci_remote_node_context_construct_buffer(sci_rnc);
+			sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
+		}
 		return SCI_SUCCESS;
+
 	case SCI_RNC_POSTING:
 	case SCI_RNC_INVALIDATING:
 	case SCI_RNC_RESUMING:
-		/* We are still waiting to post when a resume was requested. */
-		switch (sci_rnc->destination_state) {
-		case RNC_DEST_SUSPENDED:
-		case RNC_DEST_SUSPENDED_RESUME:
-			/* Previously waiting to suspend after posting.  Now
-			 * continue onto resumption.
+		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+							      cb_p);
+		else {
+			/* We are still waiting to post when a resume was
+			 * requested.
 			 */
-			sci_remote_node_context_setup_to_resume(
-				sci_rnc, cb_fn, cb_p,
-				RNC_DEST_SUSPENDED_RESUME);
-			break;
-		default:
-			sci_remote_node_context_setup_to_resume(
-				sci_rnc, cb_fn, cb_p,
-				RNC_DEST_READY);
-			break;
+			switch (sci_rnc->destination_state) {
+			case RNC_DEST_SUSPENDED:
+			case RNC_DEST_SUSPENDED_RESUME:
+				/* Previously waiting to suspend after posting.
+				 * Now continue onto resumption.
+				 */
+				sci_remote_node_context_setup_to_resume(
+					sci_rnc, cb_fn, cb_p,
+					RNC_DEST_SUSPENDED_RESUME);
+				break;
+			default:
+				sci_remote_node_context_setup_to_resume(
+					sci_rnc, cb_fn, cb_p,
+					RNC_DEST_READY);
+				break;
+			}
 		}
 		return SCI_SUCCESS;
+
 	case SCI_RNC_TX_SUSPENDED:
-	case SCI_RNC_TX_RX_SUSPENDED: {
-		struct isci_remote_device *idev = rnc_to_dev(sci_rnc);
-		struct domain_device *dev = idev->domain_dev;
-
-		/* If this is an expander attached SATA device we must
-		 * invalidate and repost the RNC since this is the only way
-		 * to clear the TCi to NCQ tag mapping table for the RNi.
-		 * All other device types we can just resume.
-		 */
-		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p,
-							RNC_DEST_READY);
+	case SCI_RNC_TX_RX_SUSPENDED:
+		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+							      cb_p);
+		else {
+			struct domain_device *dev = idev->domain_dev;
+			/* If this is an expander attached SATA device we must
+			 * invalidate and repost the RNC since this is the only
+			 * way to clear the TCi to NCQ tag mapping table for
+			 * the RNi. All other device types we can just resume.
+			 */
+			sci_remote_node_context_setup_to_resume(
+				sci_rnc, cb_fn, cb_p, RNC_DEST_READY);
 
-		if (dev_is_sata(dev) && dev->parent)
-			sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
-		else
-			sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
+			if (dev_is_sata(dev) && dev->parent)
+				sci_change_state(&sci_rnc->sm,
+						 SCI_RNC_INVALIDATING);
+			else
+				sci_change_state(&sci_rnc->sm,
+						 SCI_RNC_RESUMING);
+		}
 		return SCI_SUCCESS;
-	}
+
 	case SCI_RNC_AWAIT_SUSPENSION:
-		sci_remote_node_context_setup_to_resume(
-			sci_rnc, cb_fn, cb_p,
-			RNC_DEST_SUSPENDED_RESUME);
+		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
+			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
+							      cb_p);
+		else
+			sci_remote_node_context_setup_to_resume(
+				sci_rnc, cb_fn,	cb_p,
+				RNC_DEST_SUSPENDED_RESUME);
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 22/37] isci: Callbacks to libsas occur under scic_lock and are synchronized.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (20 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 21/37] isci: When in the abort path, defeat other resume calls until done Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 23/37] isci: Manage tag releases differently when aborting tasks Dan Williams
                   ` (14 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

This patch changes the callback mechanism to libsas to only occur while
the scic_lock is held; the abort path cleanup of I/Os also checks to make
sure IREQ_ABORT_PATH_ACTIVE is clear before proceding.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c          |   10 +++------
 drivers/scsi/isci/remote_device.c |   43 ++++++++++++++++++++++++++++++++-----
 2 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 3cc2a23..cd01e39 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1094,8 +1094,6 @@ void isci_host_completion_routine(unsigned long data)
 	list_splice_init(&ihost->requests_to_complete,
 			 &completed_request_list);
 
-	spin_unlock_irq(&ihost->scic_lock);
-
 	/* Process any completions in the list. */
 	list_for_each_safe(current_position, next_position,
 			   &completed_request_list) {
@@ -1104,7 +1102,6 @@ void isci_host_completion_routine(unsigned long data)
 				     completed_node);
 		task = isci_request_access_task(request);
 
-
 		/* Return the task to libsas */
 		if (task != NULL) {
 
@@ -1130,11 +1127,12 @@ void isci_host_completion_routine(unsigned long data)
 				}
 			}
 		}
+		if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags))
+			wake_up_all(&ihost->eventq);
 
-		spin_lock_irq(&ihost->scic_lock);
 		isci_free_tag(ihost, request->io_tag);
-		spin_unlock_irq(&ihost->scic_lock);
 	}
+	spin_unlock_irq(&ihost->scic_lock);
 
 	/* the coalesence timeout doubles at each encoding step, so
 	 * update it based on the ilog2 value of the outstanding requests
@@ -2685,8 +2683,6 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost,
 
 		index = ISCI_TAG_TCI(ireq->io_tag);
 		clear_bit(IREQ_ACTIVE, &ireq->flags);
-		if (test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
-			wake_up_all(&ihost->eventq);
 		return SCI_SUCCESS;
 	default:
 		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index d1c2a22..21a9800 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -145,6 +145,39 @@ static bool isci_compare_suspendcount(
 	return localcount != idev->rnc.suspend_count;
 }
 
+static bool isci_check_reqterm(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	struct isci_request *ireq,
+	u32 localcount)
+{
+	unsigned long flags;
+	bool res;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	res = isci_compare_suspendcount(idev, localcount)
+		&& !test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	return res;
+}
+
+static bool isci_check_devempty(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	u32 localcount)
+{
+	unsigned long flags;
+	bool res;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	res = isci_compare_suspendcount(idev, localcount)
+		&& idev->started_request_count == 0;
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	return res;
+}
+
 enum sci_status isci_remote_device_terminate_requests(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev,
@@ -179,17 +212,15 @@ enum sci_status isci_remote_device_terminate_requests(
 			sci_remote_device_terminate_req(ihost, idev, 0, ireq);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
 			wait_event(ihost->eventq,
-				   (isci_compare_suspendcount(idev,
-							      rnc_suspend_count)
-				    && !test_bit(IREQ_ACTIVE, &ireq->flags)));
+				   isci_check_reqterm(ihost, idev, ireq,
+						      rnc_suspend_count));
 		} else {
 			/* Terminate all TCs. */
 			sci_remote_device_terminate_requests(idev);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
 			wait_event(ihost->eventq,
-				   (isci_compare_suspendcount(idev,
-							      rnc_suspend_count)
-				    && idev->started_request_count == 0));
+				   isci_check_devempty(ihost, idev,
+						       rnc_suspend_count));
 		}
 		dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
 			__func__, idev);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 23/37] isci: Manage tag releases differently when aborting tasks.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (21 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 22/37] isci: Callbacks to libsas occur under scic_lock and are synchronized Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:29 ` [isci-rnc PATCH v1 24/37] isci: Fix RNC suspend call for SCI_RESUMING state Dan Williams
                   ` (13 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

When an individual request is being terminated, the request's tag
is managed in the terminate function.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c          |    3 ++-
 drivers/scsi/isci/remote_device.c |   11 +++++++----
 drivers/scsi/isci/request.h       |    1 +
 drivers/scsi/isci/task.c          |    3 ++-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index cd01e39..7061c98 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1130,7 +1130,8 @@ void isci_host_completion_routine(unsigned long data)
 		if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags))
 			wake_up_all(&ihost->eventq);
 
-		isci_free_tag(ihost, request->io_tag);
+		if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &request->flags))
+			isci_free_tag(ihost, request->io_tag);
 	}
 	spin_unlock_irq(&ihost->scic_lock);
 
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 21a9800..adeda64 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -104,15 +104,15 @@ static enum sci_status sci_remote_device_terminate_req(
 	int check_abort,
 	struct isci_request *ireq)
 {
-	dev_dbg(&ihost->pdev->dev,
-		"%s: idev=%p; flags=%lx; req=%p; req target=%p\n",
-		__func__, idev, idev->flags, ireq, ireq->target_device);
-
 	if (!test_bit(IREQ_ACTIVE, &ireq->flags) ||
 	    (ireq->target_device != idev) ||
 	    (check_abort && !test_bit(IREQ_PENDING_ABORT, &ireq->flags)))
 		return SCI_SUCCESS;
 
+	dev_dbg(&ihost->pdev->dev,
+		"%s: idev=%p; flags=%lx; req=%p; req target=%p\n",
+		__func__, idev, idev->flags, ireq, ireq->target_device);
+
 	set_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags);
 
 	return sci_controller_terminate_request(ihost, idev, ireq);
@@ -209,11 +209,14 @@ enum sci_status isci_remote_device_terminate_requests(
 			rnc_suspend_count, idev->rnc.suspend_count);
 		if (ireq) {
 			/* Terminate a specific TC. */
+			set_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
 			sci_remote_device_terminate_req(ihost, idev, 0, ireq);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
 			wait_event(ihost->eventq,
 				   isci_check_reqterm(ihost, idev, ireq,
 						      rnc_suspend_count));
+			clear_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
+			isci_free_tag(ihost, ireq->io_tag);
 		} else {
 			/* Terminate all TCs. */
 			sci_remote_device_terminate_requests(idev);
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index d12e975..1a65157 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -87,6 +87,7 @@ struct isci_request {
 	#define IREQ_PENDING_ABORT 4 /* Set == device was not suspended yet */
 	#define IREQ_TC_ABORT_POSTED 5
 	#define IREQ_ABORT_PATH_ACTIVE 6
+	#define IREQ_NO_AUTO_FREE_TAG 7 /* Set when being explicitly managed */
 	unsigned long flags;
 	/* XXX kill ttype and ttype_ptr, allocate full sas_task */
 	union ttype_ptr_union {
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index c1c6dd0..e798c6a 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -719,7 +719,8 @@ isci_task_request_complete(struct isci_host *ihost,
 	 */
 	set_bit(IREQ_TERMINATED, &ireq->flags);
 
-	isci_free_tag(ihost, ireq->io_tag);
+	if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags))
+		isci_free_tag(ihost, ireq->io_tag);
 
 	/* The task management part completes last. */
 	if (tmf_complete)


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 24/37] isci: Fix RNC suspend call for SCI_RESUMING state.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (22 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 23/37] isci: Manage tag releases differently when aborting tasks Dan Williams
@ 2012-03-23  0:29 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 25/37] isci: Wait for RNC resumption before leaving the abort path Dan Williams
                   ` (12 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Instead of immediately transitioning to the SCI_RNC_AWAIT_SUSPENSION
state, handle the SCI_RNC_RESUMING suspend transition from the
SCI_RNC_READY state like the SCI_RNC_INVALIDATING --> SCI_RNC_POSTING
transitions do now, by setting the destination state for the entry
into the READY state.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_node_context.c |   12 ++++--------
 1 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index faeae95..b698081 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -321,8 +321,6 @@ static void sci_remote_node_context_ready_state_enter(struct sci_base_state_mach
 {
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
 	enum sci_remote_node_context_destination_state dest_select;
-	scics_sds_remote_node_context_callback usr_cb = rnc->user_callback;
-	void *usr_param = rnc->user_cookie;
 	int tell_user = 1;
 
 	dest_select = rnc->destination_state;
@@ -334,12 +332,10 @@ static void sci_remote_node_context_ready_state_enter(struct sci_base_state_mach
 			rnc, rnc->suspend_reason,
 			SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
 
-		if (dest_select == RNC_DEST_SUSPENDED_RESUME) {
-			sci_remote_node_context_resume(rnc, usr_cb, usr_param);
+		if (dest_select == RNC_DEST_SUSPENDED_RESUME)
 			tell_user = 0;  /* Wait until ready again. */
-		}
 	}
-	if (tell_user && rnc->user_callback)
+	if (tell_user)
 		sci_remote_node_context_notify_user(rnc);
 }
 
@@ -584,8 +580,6 @@ enum sci_status sci_remote_node_context_suspend(
 		dest_param = sci_rnc->destination_state;
 
 	switch (state) {
-	case SCI_RNC_RESUMING:
-		break;  /* The RNC has been posted, so start the suspend. */
 	case SCI_RNC_READY:
 		break;
 	case SCI_RNC_INVALIDATING:
@@ -596,6 +590,8 @@ enum sci_status sci_remote_node_context_suspend(
 			return SCI_FAILURE_INVALID_STATE;
 		}
 		/* Fall through and handle like SCI_RNC_POSTING */
+	case SCI_RNC_RESUMING:
+		/* Fall through and handle like SCI_RNC_POSTING */
 	case SCI_RNC_POSTING:
 		/* Set the destination state to AWAIT - this signals the
 		 * entry into the SCI_RNC_READY state that a suspension


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 25/37] isci: Wait for RNC resumption before leaving the abort path.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (23 preceding siblings ...)
  2012-03-23  0:29 ` [isci-rnc PATCH v1 24/37] isci: Fix RNC suspend call for SCI_RESUMING state Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 26/37] isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs Dan Williams
                   ` (11 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

In the case of TMF execution, or device resets, wait for the RNC to fully
resume before returning to the caller.  This ensures that the remote
device will not fail I/O requests while waiting for the RNC resumption to
complete.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c |   52 ++++++++++++++++++++++++++++++++++++-
 drivers/scsi/isci/remote_device.h |    3 ++
 2 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index adeda64..37e9bde 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1289,6 +1289,48 @@ enum sci_status sci_remote_device_resume(
 	return status;
 }
 
+static void isci_remote_device_resume_from_abort_complete(void *cbparam)
+{
+	struct isci_remote_device *idev = cbparam;
+	struct isci_host *ihost = idev->owning_port->owning_controller;
+	scics_sds_remote_node_context_callback abort_resume_cb =
+		idev->abort_resume_cb;
+
+	dev_dbg(scirdev_to_dev(idev), "%s: passing-along resume: %p\n",
+		__func__, abort_resume_cb);
+
+	if (abort_resume_cb != NULL) {
+		idev->abort_resume_cb = NULL;
+		abort_resume_cb(idev->abort_resume_cbparam);
+	}
+	clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+	wake_up(&ihost->eventq);
+}
+
+
+void isci_remote_device_wait_for_resume_from_abort(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev)
+{
+	dev_dbg(scirdev_to_dev(idev), "%s: starting resume wait: %p\n",
+		 __func__, idev);
+
+	#define MAX_RESUME_MSECS 5
+	if (!wait_event_timeout(ihost->eventq,
+			       (!test_bit(IDEV_ABORT_PATH_RESUME_PENDING,
+					  &idev->flags)
+				|| test_bit(IDEV_STOP_PENDING, &idev->flags)),
+			       msecs_to_jiffies(MAX_RESUME_MSECS))) {
+
+		dev_warn(scirdev_to_dev(idev), "%s: #### Timeout waiting for "
+			 "resume: %p\n", __func__, idev);
+	}
+	clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+
+	dev_dbg(scirdev_to_dev(idev), "%s: resume wait done: %p\n",
+		 __func__, idev);
+}
+
 enum sci_status isci_remote_device_resume_from_abort(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev)
@@ -1300,12 +1342,18 @@ enum sci_status isci_remote_device_resume_from_abort(
 	/* Preserve any current resume callbacks, for instance from other
 	 * resumptions.
 	 */
+	idev->abort_resume_cb = idev->rnc.user_callback;
+	idev->abort_resume_cbparam = idev->rnc.user_cookie;
+	set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
 	clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
-	status = sci_remote_device_resume(idev, idev->rnc.user_callback,
-					  idev->rnc.user_cookie);
+	status = sci_remote_device_resume(
+			idev, isci_remote_device_resume_from_abort_complete,
+			idev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+	isci_remote_device_wait_for_resume_from_abort(ihost, idev);
 	return status;
 }
+
 /**
  * sci_remote_device_start() - This method will start the supplied remote
  *    device.  This method enables normal IO requests to flow through to the
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 53564c3..ff34c4e 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -87,6 +87,7 @@ struct isci_remote_device {
 	#define IDEV_IO_NCQERROR 5
 	#define IDEV_RNC_LLHANG_ENABLED 6
 	#define IDEV_ABORT_PATH_ACTIVE 7
+	#define IDEV_ABORT_PATH_RESUME_PENDING 8
 	unsigned long flags;
 	struct kref kref;
 	struct isci_port *isci_port;
@@ -101,6 +102,8 @@ struct isci_remote_device {
 	u32 started_request_count;
 	struct isci_request *working_request;
 	u32 not_ready_reason;
+	scics_sds_remote_node_context_callback abort_resume_cb;
+	void *abort_resume_cbparam;
 };
 
 #define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 26/37] isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (24 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 25/37] isci: Wait for RNC resumption before leaving the abort path Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 27/37] isci: Add protocol indicator for TMF requests Dan Williams
                   ` (10 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

TMF requests, unlike normal I/O requests, need to handle I/O management
conditions in the completion function because TMFs are not handled in the
completion tasklet.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/task.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index e798c6a..084f8f7 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -719,6 +719,9 @@ isci_task_request_complete(struct isci_host *ihost,
 	 */
 	set_bit(IREQ_TERMINATED, &ireq->flags);
 
+	if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+		wake_up_all(&ihost->eventq);
+
 	if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags))
 		isci_free_tag(ihost, ireq->io_tag);
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 27/37] isci: Add protocol indicator for TMF requests.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (25 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 26/37] isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 28/37] isci: Added timeouts to RNC suspensions in the abort path Dan Williams
                   ` (9 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Requests contructed as task management requests need to have the protocol
indicator set so the completion decode can observe any RNC suspension
conditions.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/request.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index df713d5..5c97102 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -3130,6 +3130,12 @@ enum sci_status sci_task_request_construct(struct isci_host *ihost,
 	if (dev->dev_type == SAS_END_DEV || dev_is_sata(dev)) {
 		set_bit(IREQ_TMF, &ireq->flags);
 		memset(ireq->tc, 0, sizeof(struct scu_task_context));
+
+		/* Set the protocol indicator. */
+		if (dev_is_sata(dev))
+			ireq->protocol = SAS_PROTOCOL_STP;
+		else
+			ireq->protocol = SAS_PROTOCOL_SSP;
 	} else
 		status = SCI_FAILURE_UNSUPPORTED_PROTOCOL;
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 28/37] isci: Added timeouts to RNC suspensions in the abort path.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (26 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 27/37] isci: Add protocol indicator for TMF requests Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 29/37] isci: Change the phy control and link reset interface for HW reasons Dan Williams
                   ` (8 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

This change adds timeouts to the RNC suspension wait.  It makes the
suspend and resume timeouts the same.

The previous resume timeout of 5 ms was too short, and timeouts were
seen in resumptions of devices in the abort task/LUN reset path - which
would receive an RNC resumed message within a tenth of a second later.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |   58 +++++++++++++++++++++++++++----
 drivers/scsi/isci/remote_node_context.c |    8 ++--
 2 files changed, 55 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 37e9bde..be9f0e0 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -207,23 +207,67 @@ enum sci_status isci_remote_device_terminate_requests(
 				"about to wait\n",
 			__func__, idev, ireq, idev->started_request_count,
 			rnc_suspend_count, idev->rnc.suspend_count);
+
+		#define MAX_SUSPEND_MSECS 10000
 		if (ireq) {
 			/* Terminate a specific TC. */
 			set_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
 			sci_remote_device_terminate_req(ihost, idev, 0, ireq);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
-			wait_event(ihost->eventq,
-				   isci_check_reqterm(ihost, idev, ireq,
-						      rnc_suspend_count));
+			if (!wait_event_timeout(ihost->eventq,
+						isci_check_reqterm(ihost, idev, ireq,
+								   rnc_suspend_count),
+						msecs_to_jiffies(MAX_SUSPEND_MSECS))) {
+
+				dev_warn(&ihost->pdev->dev, "%s host%d timeout single\n",
+					 __func__, ihost->id);
+				dev_dbg(&ihost->pdev->dev,
+					 "%s: ******* Timeout waiting for "
+					 "suspend; idev=%p, current state %s; "
+					 "started_request_count=%d, flags=%lx\n\t"
+					 "rnc_suspend_count=%d, rnc.suspend_count=%d "
+					 "RNC: current state %s, current "
+					 "suspend_type %x dest state %d;\n"
+					 "ireq=%p, ireq->flags = %lx\n",
+					 __func__, idev,
+					 dev_state_name(idev->sm.current_state_id),
+					 idev->started_request_count, idev->flags,
+					 rnc_suspend_count, idev->rnc.suspend_count,
+					 rnc_state_name(idev->rnc.sm.current_state_id),
+					 idev->rnc.suspend_type,
+					 idev->rnc.destination_state,
+					 ireq, ireq->flags);
+			}
 			clear_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
 			isci_free_tag(ihost, ireq->io_tag);
 		} else {
 			/* Terminate all TCs. */
 			sci_remote_device_terminate_requests(idev);
 			spin_unlock_irqrestore(&ihost->scic_lock, flags);
-			wait_event(ihost->eventq,
-				   isci_check_devempty(ihost, idev,
-						       rnc_suspend_count));
+			if (!wait_event_timeout(ihost->eventq,
+						isci_check_devempty(ihost, idev,
+								    rnc_suspend_count),
+						msecs_to_jiffies(MAX_SUSPEND_MSECS))) {
+
+				dev_warn(&ihost->pdev->dev, "%s host%d timeout all\n",
+					 __func__, ihost->id);
+				dev_dbg(&ihost->pdev->dev,
+					"%s: ******* Timeout waiting for "
+					"suspend; idev=%p, current state %s; "
+					"started_request_count=%d, flags=%lx\n\t"
+					"rnc_suspend_count=%d, "
+					"RNC: current state %s, "
+					"rnc.suspend_count=%d, current "
+					"suspend_type %x dest state %d\n",
+					__func__, idev,
+					dev_state_name(idev->sm.current_state_id),
+					idev->started_request_count, idev->flags,
+					rnc_suspend_count,
+					rnc_state_name(idev->rnc.sm.current_state_id),
+					idev->rnc.suspend_count,
+					idev->rnc.suspend_type,
+					idev->rnc.destination_state);
+			}
 		}
 		dev_dbg(&ihost->pdev->dev, "%s: idev=%p, wait done\n",
 			__func__, idev);
@@ -1315,7 +1359,7 @@ void isci_remote_device_wait_for_resume_from_abort(
 	dev_dbg(scirdev_to_dev(idev), "%s: starting resume wait: %p\n",
 		 __func__, idev);
 
-	#define MAX_RESUME_MSECS 5
+	#define MAX_RESUME_MSECS 10000
 	if (!wait_event_timeout(ihost->eventq,
 			       (!test_bit(IDEV_ABORT_PATH_RESUME_PENDING,
 					  &idev->flags)
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index b698081..a0a62e3 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -445,7 +445,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 			case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
 				/* We really dont care if the hardware is going to suspend
 				 * the device since it's being invalidated anyway */
-				dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+				dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
 					"%s: SCIC Remote Node Context 0x%p was "
 					"suspeneded by hardware while being "
 					"invalidated.\n", __func__, sci_rnc);
@@ -464,7 +464,7 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 			case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
 				/* We really dont care if the hardware is going to suspend
 				 * the device since it's being resumed anyway */
-				dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+				dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
 					"%s: SCIC Remote Node Context 0x%p was "
 					"suspeneded by hardware while being resumed.\n",
 					__func__, sci_rnc);
@@ -568,9 +568,9 @@ enum sci_status sci_remote_node_context_suspend(
 		RNC_DEST_UNSPECIFIED;
 
 	dev_dbg(scirdev_to_dev(idev),
-		"%s: current state %d, current suspend_type %x dest state %d,"
+		"%s: current state %s, current suspend_type %x dest state %d,"
 			" arg suspend_reason %d, arg suspend_type %x",
-		__func__, state, sci_rnc->suspend_type,
+		__func__, rnc_state_name(state), sci_rnc->suspend_type,
 		sci_rnc->destination_state, suspend_reason,
 		suspend_type);
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 29/37] isci: Change the phy control and link reset interface for HW reasons.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (27 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 28/37] isci: Added timeouts to RNC suspensions in the abort path Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 30/37] isci: Don't wait for an RNC suspend if it's being destroyed Dan Williams
                   ` (7 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

There is an apparent HW lockup caused when the PE is disabled while there
is an outstanding TC in progress.  This change puts the link into OOB to
force the TC to end before the PE is disabled.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/phy.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index 474330f..6ef3b3e 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -1387,12 +1387,14 @@ int isci_phy_control(struct asd_sas_phy *sas_phy,
 	switch (func) {
 	case PHY_FUNC_DISABLE:
 		spin_lock_irqsave(&ihost->scic_lock, flags);
+		scu_link_layer_start_oob(iphy);
 		sci_phy_stop(iphy);
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		break;
 
 	case PHY_FUNC_LINK_RESET:
 		spin_lock_irqsave(&ihost->scic_lock, flags);
+		scu_link_layer_start_oob(iphy);
 		sci_phy_stop(iphy);
 		sci_phy_start(iphy);
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 30/37] isci: Don't wait for an RNC suspend if it's being destroyed.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (28 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 29/37] isci: Change the phy control and link reset interface for HW reasons Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 31/37] isci: Restore the ATAPI device RNC management code Dan Williams
                   ` (6 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Make sure that the wait for suspend can handle the RNC destruction case.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c       |   20 ++++++++++++++++----
 drivers/scsi/isci/remote_node_context.c |    5 +++++
 drivers/scsi/isci/remote_node_context.h |    7 +++++++
 3 files changed, 28 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index be9f0e0..68ab4fb 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -142,7 +142,12 @@ static bool isci_compare_suspendcount(
 	u32 localcount)
 {
 	smp_rmb();
-	return localcount != idev->rnc.suspend_count;
+
+	/* Check for a change in the suspend count, or the RNC
+	 * being destroyed.
+	 */
+	return (localcount != idev->rnc.suspend_count)
+	    || sci_remote_node_context_is_being_destroyed(&idev->rnc);
 }
 
 static bool isci_check_reqterm(
@@ -1380,7 +1385,8 @@ enum sci_status isci_remote_device_resume_from_abort(
 	struct isci_remote_device *idev)
 {
 	unsigned long flags;
-	enum sci_status status;
+	enum sci_status status = SCI_SUCCESS;
+	int destroyed;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	/* Preserve any current resume callbacks, for instance from other
@@ -1390,11 +1396,17 @@ enum sci_status isci_remote_device_resume_from_abort(
 	idev->abort_resume_cbparam = idev->rnc.user_cookie;
 	set_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
 	clear_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags);
-	status = sci_remote_device_resume(
+	destroyed = sci_remote_node_context_is_being_destroyed(&idev->rnc);
+	if (!destroyed)
+		status = sci_remote_device_resume(
 			idev, isci_remote_device_resume_from_abort_complete,
 			idev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-	isci_remote_device_wait_for_resume_from_abort(ihost, idev);
+	if (!destroyed)
+		isci_remote_device_wait_for_resume_from_abort(ihost, idev);
+	else
+		clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
+
 	return status;
 }
 
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index a0a62e3..920c2bb 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -270,6 +270,8 @@ static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_
 static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm)
 {
 	struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm);
+	struct isci_remote_device *idev = rnc_to_dev(rnc);
+	struct isci_host *ihost = idev->owning_port->owning_controller;
 
 	/* Check to see if we have gotten back to the initial state because
 	 * someone requested to destroy the remote node context object.
@@ -277,6 +279,9 @@ static void sci_remote_node_context_initial_state_enter(struct sci_base_state_ma
 	if (sm->previous_state_id == SCI_RNC_INVALIDATING) {
 		rnc->destination_state = RNC_DEST_UNSPECIFIED;
 		sci_remote_node_context_notify_user(rnc);
+
+		smp_wmb();
+		wake_up(&ihost->eventq);
 	}
 }
 
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index c61c02e..0d4a24d 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -226,4 +226,11 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context
 int sci_remote_node_context_is_safe_to_abort(
 	struct sci_remote_node_context *sci_rnc);
 
+static inline bool sci_remote_node_context_is_being_destroyed(
+	struct sci_remote_node_context *sci_rnc)
+{
+	return ((sci_rnc->sm.current_state_id == SCI_RNC_INVALIDATING)
+		&& (sci_rnc->destination_state == RNC_DEST_FINAL))
+		|| (sci_rnc->sm.current_state_id == SCI_RNC_INITIAL);
+}
 #endif  /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 31/37] isci: Restore the ATAPI device RNC management code.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (29 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 30/37] isci: Don't wait for an RNC suspend if it's being destroyed Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 32/37] isci: Check IDEV_GONE before performing abort path operations Dan Williams
                   ` (5 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

The ATAPI specific and STP general RNC suspension code had been
incorrectly removed from the remote device code.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c |   49 ++++++++++++++++++++++---------------
 drivers/scsi/isci/remote_device.h |    2 ++
 drivers/scsi/isci/request.c       |    3 ++
 3 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 68ab4fb..48765aa 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -72,8 +72,8 @@ const char *dev_state_name(enum sci_remote_device_states state)
 }
 #undef C
 
-static enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
-						 enum sci_remote_node_suspension_reasons reason)
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+					  enum sci_remote_node_suspension_reasons reason)
 {
 	return sci_remote_node_context_suspend(&idev->rnc, reason,
 					       SCI_SOFTWARE_SUSPEND_EXPECTED_EVENT);
@@ -565,6 +565,8 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 						     u32 event_code)
 {
 	enum sci_status status;
+	struct sci_base_state_machine *sm = &idev->sm;
+	enum sci_remote_device_states state = sm->current_state_id;
 
 	switch (scu_get_event_type(event_code)) {
 	case SCU_EVENT_TYPE_RNC_OPS_MISC:
@@ -603,6 +605,30 @@ enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev,
 	if (status != SCI_SUCCESS)
 		return status;
 
+	/* Decode device-specific states that may require an RNC resume during
+	 * normal operation.  When the abort path is active, these resumes are
+	 * managed when the abort path exits.
+	 */
+	if (state == SCI_STP_DEV_ATAPI_ERROR) {
+		/* For ATAPI error state resume the RNC right away. */
+		if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
+		    scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) {
+			return sci_remote_node_context_resume(&idev->rnc,
+							      atapi_remote_device_resume_done,
+							      idev);
+		}
+	}
+
+	if (state == SCI_STP_DEV_IDLE) {
+
+		/* We pick up suspension events to handle specifically to this
+		 * state. We resume the RNC right away.
+		 */
+		if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX ||
+		    scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX)
+			status = sci_remote_node_context_resume(&idev->rnc, NULL, NULL);
+	}
+
 	return status;
 }
 
@@ -1137,21 +1163,6 @@ static void sci_stp_remote_device_ready_ncq_error_substate_enter(struct sci_base
 					     idev->not_ready_reason);
 }
 
-static void sci_stp_remote_device_atapi_error_substate_enter(
-	struct sci_base_state_machine *sm)
-{
-	struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
-
-	/* This state is entered when an I/O is decoded with an error
-	 * condition.  By this point the RNC expected suspension state is set.
-	 * The error conditions suspend the device, so unsuspend here if
-	 * possible.
-	 */
-	sci_remote_node_context_resume(&idev->rnc,
-				       atapi_remote_device_resume_done,
-				       idev);
-}
-
 static void sci_smp_remote_device_ready_idle_substate_enter(struct sci_base_state_machine *sm)
 {
 	struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm);
@@ -1202,9 +1213,7 @@ static const struct sci_base_state sci_remote_device_state_table[] = {
 	[SCI_STP_DEV_NCQ_ERROR] = {
 		.enter_state = sci_stp_remote_device_ready_ncq_error_substate_enter,
 	},
-	[SCI_STP_DEV_ATAPI_ERROR] = {
-		.enter_state = sci_stp_remote_device_atapi_error_substate_enter,
-	},
+	[SCI_STP_DEV_ATAPI_ERROR] = { },
 	[SCI_STP_DEV_AWAIT_RESET] = { },
 	[SCI_SMP_DEV_IDLE] = {
 		.enter_state = sci_smp_remote_device_ready_idle_substate_enter,
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index ff34c4e..7674caa 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -382,4 +382,6 @@ enum sci_status isci_remote_device_terminate_requests(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev,
 	struct isci_request *ireq);
+enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev,
+					  enum sci_remote_node_suspension_reasons reason);
 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 5c97102..6584ef0 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2118,6 +2118,9 @@ static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq
 		 * completion.
 		 */
 		if (ireq->stp.rsp.fis_type == FIS_REGD2H) {
+			sci_remote_device_suspend(ireq->target_device,
+						  SCI_SW_SUSPEND_NORMAL);
+
 			ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE;
 			ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID;
 			sci_change_state(&ireq->sm, SCI_REQ_COMPLETED);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 32/37] isci: Check IDEV_GONE before performing abort path operations.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (30 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 31/37] isci: Restore the ATAPI device RNC management code Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 33/37] isci: Remove obviated host callback list Dan Williams
                   ` (4 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

In the link fail path, set IDEV_GONE for every device on the domain
when the last link in the port fails.

In the abort path functions like isci_reset_device, make sure that
there has not already been a detected domain failure with the device
by checking IDEV_GONE, before performing any kind of hard reset, SMP
phy control, or TMF operation.

The check for IDEV_GONE makes sure that the device in the abort path
really has control of the port with which it is associated.  This
prevents starting hard resets at incorrect times and scheduling
unnecessary LUN resets for SATA devices.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/port.c |   23 +++++++++++++++++++
 drivers/scsi/isci/task.c |   55 ++++++++++++++++++++++++++++------------------
 2 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 87944c8..bab07c8 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -240,9 +240,32 @@ static void isci_port_link_down(struct isci_host *isci_host,
 				struct isci_phy *isci_phy,
 				struct isci_port *isci_port)
 {
+	struct isci_remote_device *isci_device;
+
 	dev_dbg(&isci_host->pdev->dev,
 		"%s: isci_port = %p\n", __func__, isci_port);
 
+	if (isci_port) {
+
+		/* check to see if this is the last phy on this port. */
+		if (isci_phy->sas_phy.port &&
+		    isci_phy->sas_phy.port->num_phys == 1) {
+			/* change the state for all devices on this port.  The
+			* next task sent to this device will be returned as
+			* SAS_TASK_UNDELIVERED, and the scsi mid layer will
+			* remove the target
+			*/
+			list_for_each_entry(isci_device,
+					    &isci_port->remote_dev_list,
+					    node) {
+				dev_dbg(&isci_host->pdev->dev,
+					"%s: isci_device = %p\n",
+					__func__, isci_device);
+				set_bit(IDEV_GONE, &isci_device->flags);
+			}
+		}
+	}
+
 	/* Notify libsas of the borken link, this will trigger calls to our
 	 * isci_port_deformed and isci_dev_gone functions.
 	 */
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 084f8f7..6bc74eb 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -421,7 +421,7 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 	struct isci_host *ihost = dev_to_ihost(dev);
 	struct isci_remote_device *idev;
 	unsigned long flags;
-	int ret;
+	int ret = TMF_RESP_FUNC_COMPLETE;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	idev = isci_get_device(dev->lldd_dev);
@@ -447,12 +447,12 @@ int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 		goto out;
 	}
 	/* All pending I/Os have been terminated and cleaned up. */
-	if (dev_is_sata(dev)) {
-		sas_ata_schedule_reset(dev);
-		ret = TMF_RESP_FUNC_COMPLETE;
-	} else {
-		/* Send the task management part of the reset. */
-		ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
+	if (!test_bit(IDEV_GONE, &idev->flags)) {
+		if (dev_is_sata(dev))
+			sas_ata_schedule_reset(dev);
+		else
+			/* Send the task management part of the reset. */
+			ret = isci_task_send_lu_reset_sas(ihost, idev, lun);
 	}
  out:
 	isci_put_device(idev);
@@ -512,8 +512,17 @@ int isci_task_abort_task(struct sas_task *task)
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	dev_warn(&ihost->pdev->dev,
-		 "%s: dev = %p, task = %p, old_request == %p\n",
-		 __func__, idev, task, old_request);
+		 "%s: dev = %p (%s%s), task = %p, old_request == %p\n",
+		 __func__, idev,
+		 (dev_is_sata(task->dev) ? "STP/SATA"
+					 : ((dev_is_expander(task->dev))
+						? "SMP"
+						: "SSP")),
+		 ((idev) ? ((test_bit(IDEV_GONE, &idev->flags))
+			   ? " IDEV_GONE"
+			   : "")
+			 : " <NULL>"),
+		 task, old_request);
 
 	/* Device reset conditions signalled in task_state_flags are the
 	 * responsbility of libsas to observe at the start of the error
@@ -552,7 +561,8 @@ int isci_task_abort_task(struct sas_task *task)
 
 	if (task->task_proto == SAS_PROTOCOL_SMP ||
 	    sas_protocol_ata(task->task_proto) ||
-	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) {
+	    test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags) ||
+	    test_bit(IDEV_GONE, &idev->flags)) {
 
 		spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
@@ -561,7 +571,8 @@ int isci_task_abort_task(struct sas_task *task)
 
 		dev_warn(&ihost->pdev->dev,
 			 "%s: %s request"
-				 " or complete_in_target (%d), thus no TMF\n",
+				 " or complete_in_target (%d), "
+				 "or IDEV_GONE (%d), thus no TMF\n",
 			 __func__,
 			 ((task->task_proto == SAS_PROTOCOL_SMP)
 			  ? "SMP"
@@ -570,7 +581,8 @@ int isci_task_abort_task(struct sas_task *task)
 				: "<other>")
 			  ),
 			 test_bit(IREQ_COMPLETE_IN_TARGET,
-				  &old_request->flags));
+				  &old_request->flags),
+			 test_bit(IDEV_GONE, &idev->flags));
 
 		spin_lock_irqsave(&task->task_state_lock, flags);
 		task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR |
@@ -734,7 +746,7 @@ static int isci_reset_device(struct isci_host *ihost,
 			     struct domain_device *dev,
 			     struct isci_remote_device *idev)
 {
-	int rc = TMF_RESP_FUNC_COMPLETE, reset_stat;
+	int rc = TMF_RESP_FUNC_COMPLETE, reset_stat = -1;
 	struct sas_phy *phy = sas_get_local_phy(dev);
 	struct isci_port *iport = dev->port->lldd_port;
 
@@ -752,14 +764,15 @@ static int isci_reset_device(struct isci_host *ihost,
 	 * primary duty of this function is to cleanup tasks, so that is the
 	 * relevant status.
 	 */
-
-	if (scsi_is_sas_phy_local(phy)) {
-		struct isci_phy *iphy = &ihost->phys[phy->number];
-
-		reset_stat = isci_port_perform_hard_reset(ihost, iport, iphy);
-	} else
-		reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
-
+	if (!test_bit(IDEV_GONE, &idev->flags)) {
+		if (scsi_is_sas_phy_local(phy)) {
+			struct isci_phy *iphy = &ihost->phys[phy->number];
+
+			reset_stat = isci_port_perform_hard_reset(ihost, iport,
+								  iphy);
+		} else
+			reset_stat = sas_phy_reset(phy, !dev_is_sata(dev));
+	}
 	/* Explicitly resume the RNC here, since there was no task sent. */
 	isci_remote_device_resume_from_abort(ihost, idev);
 


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 33/37] isci: Remove obviated host callback list.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (31 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 32/37] isci: Check IDEV_GONE before performing abort path operations Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:30 ` [isci-rnc PATCH v1 34/37] isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock Dan Williams
                   ` (3 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Since the callbacks to libsas now occur under scic_lock, there is no
longer any reason to save the completed requests in a separate list
for completion to libsas.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c    |   78 ++++++++++++++-----------------------------
 drivers/scsi/isci/host.h    |    2 +
 drivers/scsi/isci/init.c    |    1 -
 drivers/scsi/isci/request.c |   14 ++------
 drivers/scsi/isci/request.h |    2 -
 5 files changed, 31 insertions(+), 66 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 7061c98..f26ff0f 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1066,6 +1066,32 @@ static void sci_controller_completion_handler(struct isci_host *ihost)
 	writel(0, &ihost->smu_registers->interrupt_mask);
 }
 
+void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task)
+{
+	task->lldd_task = NULL;
+	if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags) &&
+	    !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+		if (test_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags)) {
+			/* Normal notification (task_done) */
+			dev_dbg(&ihost->pdev->dev,
+				"%s: Normal - ireq/task = %p/%p\n",
+				__func__, ireq, task);
+
+			task->task_done(task);
+		} else {
+			dev_dbg(&ihost->pdev->dev,
+				"%s: Error - ireq/task = %p/%p\n",
+				__func__, ireq, task);
+
+			sas_task_abort(task);
+		}
+	}
+	if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+		wake_up_all(&ihost->eventq);
+
+	if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags))
+		isci_free_tag(ihost, ireq->io_tag);
+}
 /**
  * isci_host_completion_routine() - This function is the delayed service
  *    routine that calls the sci core library's completion handler. It's
@@ -1077,62 +1103,10 @@ static void sci_controller_completion_handler(struct isci_host *ihost)
 void isci_host_completion_routine(unsigned long data)
 {
 	struct isci_host *ihost = (struct isci_host *)data;
-	struct list_head    completed_request_list;
-	struct list_head    *current_position;
-	struct list_head    *next_position;
-	struct isci_request *request;
-	struct sas_task     *task;
 	u16 active;
 
-	INIT_LIST_HEAD(&completed_request_list);
-
 	spin_lock_irq(&ihost->scic_lock);
-
 	sci_controller_completion_handler(ihost);
-
-	/* Take the lists of completed I/Os from the host. */
-	list_splice_init(&ihost->requests_to_complete,
-			 &completed_request_list);
-
-	/* Process any completions in the list. */
-	list_for_each_safe(current_position, next_position,
-			   &completed_request_list) {
-
-		request = list_entry(current_position, struct isci_request,
-				     completed_node);
-		task = isci_request_access_task(request);
-
-		/* Return the task to libsas */
-		if (task != NULL) {
-
-			task->lldd_task = NULL;
-			if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags) &&
-			    !(task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
-				if (test_bit(IREQ_COMPLETE_IN_TARGET,
-					     &request->flags)) {
-
-					/* Normal notification (task_done) */
-					dev_dbg(&ihost->pdev->dev, "%s: Normal"
-						" - request/task = %p/%p\n",
-						__func__, request, task);
-
-					task->task_done(task);
-				} else {
-					dev_warn(&ihost->pdev->dev,
-						 "%s: Error - request/task"
-						 " = %p/%p\n",
-						 __func__, request, task);
-
-					sas_task_abort(task);
-				}
-			}
-		}
-		if (test_and_clear_bit(IREQ_ABORT_PATH_ACTIVE, &request->flags))
-			wake_up_all(&ihost->eventq);
-
-		if (!test_bit(IREQ_NO_AUTO_FREE_TAG, &request->flags))
-			isci_free_tag(ihost, request->io_tag);
-	}
 	spin_unlock_irq(&ihost->scic_lock);
 
 	/* the coalesence timeout doubles at each encoding step, so
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index f8f2c9c..81d96f3 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -202,7 +202,6 @@ struct isci_host {
 	wait_queue_head_t eventq;
 	struct Scsi_Host *shost;
 	struct tasklet_struct completion_tasklet;
-	struct list_head requests_to_complete;
 	spinlock_t scic_lock;
 	struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
 	struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
@@ -466,6 +465,7 @@ void isci_host_scan_start(struct Scsi_Host *);
 u16 isci_alloc_tag(struct isci_host *ihost);
 enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
 void isci_tci_free(struct isci_host *ihost, u16 tci);
+void ireq_done(struct isci_host *ihost, struct isci_request *ireq, struct sas_task *task);
 
 int isci_host_init(struct isci_host *);
 void isci_host_completion_routine(unsigned long data);
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 2a781c2..5ae27fb 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -559,7 +559,6 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
 		return NULL;
 	}
 
-	INIT_LIST_HEAD(&ihost->requests_to_complete);
 	for (i = 0; i < SCI_MAX_PORTS; i++) {
 		struct isci_port *iport = &ihost->ports[i];
 
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 6584ef0..d5c80ad 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2748,13 +2748,9 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 	enum exec_status status = SAS_ABORTED_TASK;
 
 	dev_dbg(&ihost->pdev->dev,
-		"%s: request = %p, task = %p,\n"
+		"%s: request = %p, task = %p, "
 		"task->data_dir = %d completion_status = 0x%x\n",
-		__func__,
-		request,
-		task,
-		task->data_dir,
-		completion_status);
+		__func__, request, task, task->data_dir, completion_status);
 
 	/* The request is done from an SCU HW perspective. */
 
@@ -2955,9 +2951,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 	}
 	spin_unlock_irqrestore(&task->task_state_lock, task_flags);
 
-	/* Add to the completed list. */
-	list_add(&request->completed_node, &ihost->requests_to_complete);
-
 	/* complete the io request to the core. */
 	sci_controller_complete_io(ihost, request->target_device, request);
 
@@ -2966,6 +2959,8 @@ static void isci_request_io_request_complete(struct isci_host *ihost,
 	 * task to recognize the already completed case.
 	 */
 	set_bit(IREQ_TERMINATED, &request->flags);
+
+	ireq_done(ihost, request, task);
 }
 
 static void sci_request_started_state_enter(struct sci_base_state_machine *sm)
@@ -3416,7 +3411,6 @@ static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 t
 	ireq->io_request_completion = NULL;
 	ireq->flags = 0;
 	ireq->num_sg_entries = 0;
-	INIT_LIST_HEAD(&ireq->completed_node);
 
 	return ireq;
 }
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 1a65157..aff9531 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -95,8 +95,6 @@ struct isci_request {
 		struct isci_tmf *tmf_task_ptr;  /* When ttype==tmf_task */
 	} ttype_ptr;
 	struct isci_host *isci_host;
-	/* For use in the requests_to_{complete|abort} lists: */
-	struct list_head completed_node;
 	dma_addr_t request_daddr;
 	dma_addr_t zero_scatter_daddr;
 	unsigned int num_sg_entries;


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 34/37] isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (32 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 33/37] isci: Remove obviated host callback list Dan Williams
@ 2012-03-23  0:30 ` Dan Williams
  2012-03-23  0:31 ` [isci-rnc PATCH v1 35/37] isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition Dan Williams
                   ` (2 subsequent siblings)
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:30 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

Since there is a possibilty of a timeout waiting for the RNC suspension,
handle the exit case from the task termination under scic_lock, and leave
the tag allocated if the termination timed-out.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_device.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 48765aa..a3a6487 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -243,8 +243,11 @@ enum sci_status isci_remote_device_terminate_requests(
 					 idev->rnc.destination_state,
 					 ireq, ireq->flags);
 			}
+			spin_lock_irqsave(&ihost->scic_lock, flags);
 			clear_bit(IREQ_NO_AUTO_FREE_TAG, &ireq->flags);
-			isci_free_tag(ihost, ireq->io_tag);
+			if (!test_bit(IREQ_ABORT_PATH_ACTIVE, &ireq->flags))
+				isci_free_tag(ihost, ireq->io_tag);
+			spin_unlock_irqrestore(&ihost->scic_lock, flags);
 		} else {
 			/* Terminate all TCs. */
 			sci_remote_device_terminate_requests(idev);


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 35/37] isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (33 preceding siblings ...)
  2012-03-23  0:30 ` [isci-rnc PATCH v1 34/37] isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock Dan Williams
@ 2012-03-23  0:31 ` Dan Williams
  2012-03-23  0:31 ` [isci-rnc PATCH v1 36/37] isci: Fixed RNC bug that lost the suspension or resumption during destroy Dan Williams
  2012-03-23  0:31 ` [isci-rnc PATCH v1 37/37] isci: End the RNC resumption wait when the RNC is destroyed Dan Williams
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:31 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

The RNC state machine would incorrectly transition from
SCI_RNC_AWAIT_SUSPENSION directly to SCI_RNC_INVALIDATING when a destruct
request was made.  This would skip the increment of the suspension count
and the abort of pending TCs (although the invalidating state would at
least cleanup outstanding TCs).

Instead, the RNC will transition to SCI_RNC_SUSPENDED and then start the
destruction process.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_node_context.c |   18 +++++++++++++-----
 1 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 920c2bb..6f0b61b 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -222,13 +222,19 @@ static void sci_remote_node_context_notify_user(
 
 static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc)
 {
-	if ((rnc->destination_state == RNC_DEST_READY) ||
-	    (rnc->destination_state == RNC_DEST_SUSPENDED_RESUME)) {
+	switch (rnc->destination_state) {
+	case RNC_DEST_READY:
+	case RNC_DEST_SUSPENDED_RESUME:
 		rnc->destination_state = RNC_DEST_READY;
+		/* Fall through... */
+	case RNC_DEST_FINAL:
 		sci_remote_node_context_resume(rnc, rnc->user_callback,
-						    rnc->user_cookie);
-	} else
+					       rnc->user_cookie);
+		break;
+	default:
 		rnc->destination_state = RNC_DEST_UNSPECIFIED;
+		break;
+	}
 }
 
 static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc)
@@ -539,10 +545,12 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 	case SCI_RNC_READY:
 	case SCI_RNC_TX_SUSPENDED:
 	case SCI_RNC_TX_RX_SUSPENDED:
-	case SCI_RNC_AWAIT_SUSPENSION:
 		sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
 		sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
 		return SCI_SUCCESS;
+	case SCI_RNC_AWAIT_SUSPENSION:
+		sci_remote_node_context_setup_to_destroy(sci_rnc, cb_fn, cb_p);
+		return SCI_SUCCESS;
 	case SCI_RNC_INITIAL:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
 			 "%s: invalid state: %s\n", __func__,


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 36/37] isci: Fixed RNC bug that lost the suspension or resumption during destroy
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (34 preceding siblings ...)
  2012-03-23  0:31 ` [isci-rnc PATCH v1 35/37] isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition Dan Williams
@ 2012-03-23  0:31 ` Dan Williams
  2012-03-23  0:31 ` [isci-rnc PATCH v1 37/37] isci: End the RNC resumption wait when the RNC is destroyed Dan Williams
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:31 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

This fix corrects the saving of resume parameters when the destruction
of the RNC has already been directed, and makes sure not to overwrite
the RNC destruction callbacks.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/remote_node_context.c |   96 ++++++++++++-------------------
 1 files changed, 38 insertions(+), 58 deletions(-)

diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 6f0b61b..f5792a9 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -160,15 +160,6 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
 	rnc->ssp.oaf_source_zone_group = 0;
 	rnc->ssp.oaf_more_compatibility_features = 0;
 }
-
-static void sci_remote_node_context_save_cbparams(
-	struct sci_remote_node_context *sci_rnc,
-	scics_sds_remote_node_context_callback callback,
-	void *callback_parameter)
-{
-	sci_rnc->user_callback = callback;
-	sci_rnc->user_cookie   = callback_parameter;
-}
 /**
  *
  * @sci_rnc:
@@ -187,9 +178,10 @@ static void sci_remote_node_context_setup_to_resume(
 {
 	if (sci_rnc->destination_state != RNC_DEST_FINAL) {
 		sci_rnc->destination_state = dest_param;
-		if (callback != NULL)
-			sci_remote_node_context_save_cbparams(
-				sci_rnc, callback, callback_parameter);
+		if (callback != NULL) {
+			sci_rnc->user_callback = callback;
+			sci_rnc->user_cookie   = callback_parameter;
+		}
 	}
 }
 
@@ -610,7 +602,8 @@ enum sci_status sci_remote_node_context_suspend(
 		 * entry into the SCI_RNC_READY state that a suspension
 		 * needs to be done immediately.
 		 */
-		sci_rnc->destination_state = RNC_DEST_SUSPENDED;
+		if (sci_rnc->destination_state != RNC_DEST_FINAL)
+			sci_rnc->destination_state = RNC_DEST_SUSPENDED;
 		sci_rnc->suspend_type = suspend_type;
 		sci_rnc->suspend_reason = suspend_reason;
 		return SCI_SUCCESS;
@@ -680,12 +673,9 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 		if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
 			return SCI_FAILURE_INVALID_STATE;
 
-		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
-			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
-							      cb_p);
-		else {
-			sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn,
-							cb_p, RNC_DEST_READY);
+		sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn,	cb_p,
+							RNC_DEST_READY);
+		if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) {
 			sci_remote_node_context_construct_buffer(sci_rnc);
 			sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING);
 		}
@@ -694,38 +684,30 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 	case SCI_RNC_POSTING:
 	case SCI_RNC_INVALIDATING:
 	case SCI_RNC_RESUMING:
-		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
-			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
-							      cb_p);
-		else {
-			/* We are still waiting to post when a resume was
-			 * requested.
+		/* We are still waiting to post when a resume was
+		 * requested.
+		 */
+		switch (sci_rnc->destination_state) {
+		case RNC_DEST_SUSPENDED:
+		case RNC_DEST_SUSPENDED_RESUME:
+			/* Previously waiting to suspend after posting.
+			 * Now continue onto resumption.
 			 */
-			switch (sci_rnc->destination_state) {
-			case RNC_DEST_SUSPENDED:
-			case RNC_DEST_SUSPENDED_RESUME:
-				/* Previously waiting to suspend after posting.
-				 * Now continue onto resumption.
-				 */
-				sci_remote_node_context_setup_to_resume(
-					sci_rnc, cb_fn, cb_p,
-					RNC_DEST_SUSPENDED_RESUME);
-				break;
-			default:
-				sci_remote_node_context_setup_to_resume(
-					sci_rnc, cb_fn, cb_p,
-					RNC_DEST_READY);
-				break;
-			}
+			sci_remote_node_context_setup_to_resume(
+				sci_rnc, cb_fn, cb_p,
+				RNC_DEST_SUSPENDED_RESUME);
+			break;
+		default:
+			sci_remote_node_context_setup_to_resume(
+				sci_rnc, cb_fn, cb_p,
+				RNC_DEST_READY);
+			break;
 		}
 		return SCI_SUCCESS;
 
 	case SCI_RNC_TX_SUSPENDED:
 	case SCI_RNC_TX_RX_SUSPENDED:
-		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
-			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
-							      cb_p);
-		else {
+		{
 			struct domain_device *dev = idev->domain_dev;
 			/* If this is an expander attached SATA device we must
 			 * invalidate and repost the RNC since this is the only
@@ -735,23 +717,21 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 			sci_remote_node_context_setup_to_resume(
 				sci_rnc, cb_fn, cb_p, RNC_DEST_READY);
 
-			if (dev_is_sata(dev) && dev->parent)
-				sci_change_state(&sci_rnc->sm,
-						 SCI_RNC_INVALIDATING);
-			else
-				sci_change_state(&sci_rnc->sm,
-						 SCI_RNC_RESUMING);
+			if (!test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags)) {
+				if ((dev_is_sata(dev) && dev->parent) ||
+				    (sci_rnc->destination_state == RNC_DEST_FINAL))
+					sci_change_state(&sci_rnc->sm,
+							 SCI_RNC_INVALIDATING);
+				else
+					sci_change_state(&sci_rnc->sm,
+							 SCI_RNC_RESUMING);
+			}
 		}
 		return SCI_SUCCESS;
 
 	case SCI_RNC_AWAIT_SUSPENSION:
-		if (test_bit(IDEV_ABORT_PATH_ACTIVE, &idev->flags))
-			sci_remote_node_context_save_cbparams(sci_rnc, cb_fn,
-							      cb_p);
-		else
-			sci_remote_node_context_setup_to_resume(
-				sci_rnc, cb_fn,	cb_p,
-				RNC_DEST_SUSPENDED_RESUME);
+		sci_remote_node_context_setup_to_resume(
+			sci_rnc, cb_fn, cb_p, RNC_DEST_SUSPENDED_RESUME);
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),


^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [isci-rnc PATCH v1 37/37] isci: End the RNC resumption wait when the RNC is destroyed.
  2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
                   ` (35 preceding siblings ...)
  2012-03-23  0:31 ` [isci-rnc PATCH v1 36/37] isci: Fixed RNC bug that lost the suspension or resumption during destroy Dan Williams
@ 2012-03-23  0:31 ` Dan Williams
  36 siblings, 0 replies; 38+ messages in thread
From: Dan Williams @ 2012-03-23  0:31 UTC (permalink / raw)
  To: linux-scsi; +Cc: Jeff Skirvin

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

While the RNC is suspended for I/O cleanup, the remote device can be
stopped and the RNC setup for destruction.  These changes accomodate that
case in the abort path.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.h                |    5 +++++
 drivers/scsi/isci/remote_device.c       |   29 +++++++++++++++++++++--------
 drivers/scsi/isci/remote_node_context.c |    4 ++++
 drivers/scsi/isci/remote_node_context.h |    6 +++---
 4 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 81d96f3..a8cc280 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -333,6 +333,11 @@ static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
 	return dev->port->ha->lldd_ha;
 }
 
+static inline struct isci_host *idev_to_ihost(struct isci_remote_device *idev)
+{
+	return dev_to_ihost(idev->domain_dev);
+}
+
 /* we always use protocol engine group zero */
 #define ISCI_PEG 0
 
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index a3a6487..c3aa6c5 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1368,27 +1368,40 @@ static void isci_remote_device_resume_from_abort_complete(void *cbparam)
 	wake_up(&ihost->eventq);
 }
 
+static bool isci_remote_device_test_resume_done(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev)
+{
+	unsigned long flags;
+	bool done;
+
+	spin_lock_irqsave(&ihost->scic_lock, flags);
+	done = !test_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags)
+		|| test_bit(IDEV_STOP_PENDING, &idev->flags)
+		|| sci_remote_node_context_is_being_destroyed(&idev->rnc);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+	return done;
+}
 
 void isci_remote_device_wait_for_resume_from_abort(
 	struct isci_host *ihost,
 	struct isci_remote_device *idev)
 {
-	dev_dbg(scirdev_to_dev(idev), "%s: starting resume wait: %p\n",
+	dev_dbg(&ihost->pdev->dev, "%s: starting resume wait: %p\n",
 		 __func__, idev);
 
 	#define MAX_RESUME_MSECS 10000
 	if (!wait_event_timeout(ihost->eventq,
-			       (!test_bit(IDEV_ABORT_PATH_RESUME_PENDING,
-					  &idev->flags)
-				|| test_bit(IDEV_STOP_PENDING, &idev->flags)),
-			       msecs_to_jiffies(MAX_RESUME_MSECS))) {
+				isci_remote_device_test_resume_done(ihost, idev),
+				msecs_to_jiffies(MAX_RESUME_MSECS))) {
 
-		dev_warn(scirdev_to_dev(idev), "%s: #### Timeout waiting for "
+		dev_warn(&ihost->pdev->dev, "%s: #### Timeout waiting for "
 			 "resume: %p\n", __func__, idev);
 	}
 	clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
 
-	dev_dbg(scirdev_to_dev(idev), "%s: resume wait done: %p\n",
+	dev_dbg(&ihost->pdev->dev, "%s: resume wait done: %p\n",
 		 __func__, idev);
 }
 
@@ -1414,7 +1427,7 @@ enum sci_status isci_remote_device_resume_from_abort(
 			idev, isci_remote_device_resume_from_abort_complete,
 			idev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
-	if (!destroyed)
+	if (!destroyed && (status == SCI_SUCCESS))
 		isci_remote_device_wait_for_resume_from_abort(ihost, idev);
 	else
 		clear_bit(IDEV_ABORT_PATH_RESUME_PENDING, &idev->flags);
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index f5792a9..1910100 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -190,9 +190,13 @@ static void sci_remote_node_context_setup_to_destroy(
 	scics_sds_remote_node_context_callback callback,
 	void *callback_parameter)
 {
+	struct isci_host *ihost = idev_to_ihost(rnc_to_dev(sci_rnc));
+
 	sci_rnc->destination_state = RNC_DEST_FINAL;
 	sci_rnc->user_callback     = callback;
 	sci_rnc->user_cookie       = callback_parameter;
+
+	wake_up(&ihost->eventq);
 }
 
 /**
diff --git a/drivers/scsi/isci/remote_node_context.h b/drivers/scsi/isci/remote_node_context.h
index 0d4a24d..a703b9c 100644
--- a/drivers/scsi/isci/remote_node_context.h
+++ b/drivers/scsi/isci/remote_node_context.h
@@ -229,8 +229,8 @@ int sci_remote_node_context_is_safe_to_abort(
 static inline bool sci_remote_node_context_is_being_destroyed(
 	struct sci_remote_node_context *sci_rnc)
 {
-	return ((sci_rnc->sm.current_state_id == SCI_RNC_INVALIDATING)
-		&& (sci_rnc->destination_state == RNC_DEST_FINAL))
-		|| (sci_rnc->sm.current_state_id == SCI_RNC_INITIAL);
+	return (sci_rnc->destination_state == RNC_DEST_FINAL)
+		|| ((sci_rnc->sm.current_state_id == SCI_RNC_INITIAL)
+		    && (sci_rnc->destination_state == RNC_DEST_UNSPECIFIED));
 }
 #endif  /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */


^ permalink raw reply related	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2012-03-23  0:15 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
2012-03-23  0:27 ` [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions Dan Williams
2012-03-23  0:27 ` [isci-rnc PATCH v1 02/37] isci: Fixed bug in resumption from RNC Tx/Rx suspend state Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 03/37] isci: Handle all suspending TC completions Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 04/37] isci: Terminate outstanding TCs on TX/RX RNC suspensions Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 05/37] isci: Manage device suspensions during TC terminations Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 06/37] isci: Remote device must be suspended for NCQ cleanup Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 07/37] isci: Remote device stop also suspends the RNC and terminates I/O Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 08/37] isci: Escalate to I_T_Nexus_Reset when the device is gone Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 09/37] isci: Redesign device suspension, abort, cleanup Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 10/37] isci: Add suspension cases for RNC INVALIDATING, POSTING states Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 11/37] isci: Device access in the error path does not depend on IDEV_GONE Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 12/37] isci: All pending TCs are terminated when the RNC is invalidated Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 13/37] isci: Only set IDEV_GONE in the device stop path Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 14/37] isci: Remove isci_device reqs_in_process and dev_node from isci_device Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 15/37] isci: Distinguish between remote device suspension cases Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 16/37] isci: Fix the terminated I/O to not call sas_task_abort() Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 17/37] isci: Save the suspension hint for upcoming suspensions Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 18/37] isci: Manage the LLHANG timer enable/disable per-device Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 19/37] isci: Make sure all TCs are terminated and cleaned in LUN reset Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 20/37] isci: Implement waiting for suspend in the abort path Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 21/37] isci: When in the abort path, defeat other resume calls until done Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 22/37] isci: Callbacks to libsas occur under scic_lock and are synchronized Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 23/37] isci: Manage tag releases differently when aborting tasks Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 24/37] isci: Fix RNC suspend call for SCI_RESUMING state Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 25/37] isci: Wait for RNC resumption before leaving the abort path Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 26/37] isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 27/37] isci: Add protocol indicator for TMF requests Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 28/37] isci: Added timeouts to RNC suspensions in the abort path Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 29/37] isci: Change the phy control and link reset interface for HW reasons Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 30/37] isci: Don't wait for an RNC suspend if it's being destroyed Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 31/37] isci: Restore the ATAPI device RNC management code Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 32/37] isci: Check IDEV_GONE before performing abort path operations Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 33/37] isci: Remove obviated host callback list Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 34/37] isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 35/37] isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 36/37] isci: Fixed RNC bug that lost the suspension or resumption during destroy Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 37/37] isci: End the RNC resumption wait when the RNC is destroyed Dan Williams

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.