All of lore.kernel.org
 help / color / mirror / Atom feed
* [isci PATCH v2 00/18] isci: suspend/resume support + general updates
@ 2012-03-11  7:27 Dan Williams
  2012-03-11  7:27 ` [isci PATCH v2 01/18] isci: improve 'invalid state' warnings Dan Williams
                   ` (17 more replies)
  0 siblings, 18 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:27 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

Changes since v1: http://marc.info/?l=linux-scsi&m=132886463201718&w=2

This series has been rebased on top of v10 of the libsas reworks, merged
with a recent scsi-rc-fixes (commit fea6d60).

1/ PATCH 1 - 3, 6, 11, 15: Cleanups identified along the way towards
   implementing the below fixes and features.

2/ PATCH 4, 9, 13, 18: Fixes to discovery in both the driver and libsas.

3/ PATCH 7 - 8, 12, 14, 16 - 17:  Suspend support.  The approach taken
   with suspend/resume support is to put the bulk of the responsibility on
   libsas.  The lldd is free to tear down its links and domain_device info
   with the knowledge that libsas will handle recovering those connections
   and devices at resume time.
  
---

[isci PATCH v2 01/18] isci: improve 'invalid state' warnings
[isci PATCH v2 02/18] isci: kill ->is_direct_attached
[isci PATCH v2 03/18] isci: kill sci_phy_protocol and sci_request_protocol
[isci PATCH v2 04/18] isci: Don't filter BROADCAST CHANGE primitives
[isci PATCH v2 05/18] isci: kill ->status, and ->state_lock in isci_host
[isci PATCH v2 06/18] isci: kill isci_port.domain_dev_list
[isci PATCH v2 07/18] isci: refactor initialization for S3/S4
[isci PATCH v2 08/18] isci: fix controller stop
[isci PATCH v2 09/18] isci: fix 'link-up' events occur after 'start-complete'
[isci PATCH v2 10/18] isci: fix interrupt disable
[isci PATCH v2 11/18] isci: kill isci_host.shost
[isci PATCH v2 12/18] libata: make ata_print_id atomic
[isci PATCH v2 13/18] libsas: continue revalidation
[isci PATCH v2 14/18] libata: export ata_port suspend/resume infrastructure for sas
[isci PATCH v2 15/18] libsas: drop sata port multiplier infrastructure
[isci PATCH v2 16/18] libsas: suspend / resume support
[isci PATCH v2 17/18] isci: implement suspend/resume support
[isci PATCH v2 18/18] isci: Changes in COMSAS timings enabling ISCI to detect buggy disc drives.

 drivers/ata/libata-core.c                     |   62 ++-
 drivers/ata/libata-scsi.c                     |    4 
 drivers/ata/libata.h                          |    2 
 drivers/scsi/isci/host.c                      |  564 +++++++++----------------
 drivers/scsi/isci/host.h                      |  118 +----
 drivers/scsi/isci/init.c                      |  271 +++++++++++-
 drivers/scsi/isci/phy.c                       |   74 +++
 drivers/scsi/isci/phy.h                       |    9 
 drivers/scsi/isci/port.c                      |   21 -
 drivers/scsi/isci/port.h                      |    6 
 drivers/scsi/isci/port_config.c               |   18 -
 drivers/scsi/isci/probe_roms.c                |   12 -
 drivers/scsi/isci/probe_roms.h                |    2 
 drivers/scsi/isci/registers.h                 |    8 
 drivers/scsi/isci/remote_device.c             |   29 -
 drivers/scsi/isci/remote_device.h             |    1 
 drivers/scsi/isci/remote_node_context.c       |   60 +--
 drivers/scsi/isci/request.c                   |   19 -
 drivers/scsi/isci/request.h                   |    9 
 drivers/scsi/isci/unsolicited_frame_control.c |   30 -
 drivers/scsi/isci/unsolicited_frame_control.h |    6 
 drivers/scsi/libsas/sas_ata.c                 |   86 ++++
 drivers/scsi/libsas/sas_discover.c            |   74 +++
 drivers/scsi/libsas/sas_dump.c                |    1 
 drivers/scsi/libsas/sas_event.c               |    4 
 drivers/scsi/libsas/sas_expander.c            |    8 
 drivers/scsi/libsas/sas_init.c                |   90 ++++
 drivers/scsi/libsas/sas_internal.h            |    2 
 drivers/scsi/libsas/sas_phy.c                 |   21 +
 drivers/scsi/libsas/sas_port.c                |   52 ++
 drivers/scsi/libsas/sas_scsi_host.c           |    2 
 include/linux/libata.h                        |    2 
 include/scsi/libsas.h                         |   21 +
 include/scsi/sas.h                            |    1 
 include/scsi/sas_ata.h                        |   10 
 35 files changed, 1017 insertions(+), 682 deletions(-)

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

* [isci PATCH v2 01/18] isci: improve 'invalid state' warnings
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
@ 2012-03-11  7:27 ` Dan Williams
  2012-03-11  7:27 ` [isci PATCH v2 02/18] isci: kill ->is_direct_attached Dan Williams
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:27 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

Convert controller state machine warnings to emit the state number (it
missed the number to string conversion, but since these error rarely
happen not much motivation to go further).

Fix up the rnc warnings to use the state name.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c                |   33 +++++++++++++++----------------
 drivers/scsi/isci/remote_node_context.c |   33 +++++++++++++++++++------------
 2 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index d4bf9c1..3822ffb 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -987,9 +987,8 @@ static enum sci_status sci_controller_start(struct isci_host *ihost,
 	u16 index;
 
 	if (ihost->sm.current_state_id != SCIC_INITIALIZED) {
-		dev_warn(&ihost->pdev->dev,
-			 "SCIC Controller start operation requested in "
-			 "invalid state\n");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1213,9 +1212,8 @@ static void isci_host_completion_routine(unsigned long data)
 static enum sci_status sci_controller_stop(struct isci_host *ihost, u32 timeout)
 {
 	if (ihost->sm.current_state_id != SCIC_READY) {
-		dev_warn(&ihost->pdev->dev,
-			 "SCIC Controller stop operation requested in "
-			 "invalid state\n");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -1250,9 +1248,8 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost)
 		sci_change_state(&ihost->sm, SCIC_RESETTING);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(&ihost->pdev->dev,
-			 "SCIC Controller reset operation requested in "
-			 "invalid state\n");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -2279,9 +2276,8 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost)
 	unsigned long i, state, val;
 
 	if (ihost->sm.current_state_id != SCIC_RESET) {
-		dev_warn(&ihost->pdev->dev,
-			 "SCIC Controller initialize operation requested "
-			 "in invalid state\n");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -2842,7 +2838,8 @@ enum sci_status sci_controller_start_io(struct isci_host *ihost,
 	enum sci_status status;
 
 	if (ihost->sm.current_state_id != SCIC_READY) {
-		dev_warn(&ihost->pdev->dev, "invalid state to start I/O");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -2866,8 +2863,8 @@ enum sci_status sci_controller_terminate_request(struct isci_host *ihost,
 	enum sci_status status;
 
 	if (ihost->sm.current_state_id != SCIC_READY) {
-		dev_warn(&ihost->pdev->dev,
-			 "invalid state to terminate request\n");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -2915,7 +2912,8 @@ enum sci_status sci_controller_complete_io(struct isci_host *ihost,
 		clear_bit(IREQ_ACTIVE, &ireq->flags);
 		return SCI_SUCCESS;
 	default:
-		dev_warn(&ihost->pdev->dev, "invalid state to complete I/O");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -2926,7 +2924,8 @@ enum sci_status sci_controller_continue_io(struct isci_request *ireq)
 	struct isci_host *ihost = ireq->owning_controller;
 
 	if (ihost->sm.current_state_id != SCIC_READY) {
-		dev_warn(&ihost->pdev->dev, "invalid state to continue I/O");
+		dev_warn(&ihost->pdev->dev, "%s invalid state: %d\n",
+			 __func__, ihost->sm.current_state_id);
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 3a94634..994ec0c 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -443,14 +443,16 @@ enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_con
 		break;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			 "%s: invalid state: %s\n", __func__,
+			 rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 	return SCI_SUCCESS;
 
  out:
 	dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-		 "%s: code: %#x state: %d\n", __func__, event_code, state);
+		 "%s: code: %#x state: %s\n", __func__, event_code,
+		 rnc_state_name(state));
 	return SCI_FAILURE;
 
 }
@@ -477,7 +479,8 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 		return SCI_SUCCESS;
 	case SCI_RNC_INITIAL:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			 "%s: invalid state: %s\n", __func__,
+			 rnc_state_name(state));
 		/* We have decided that the destruct request on the remote node context
 		 * can not fail since it is either in the initial/destroyed state or is
 		 * can be destroyed.
@@ -485,7 +488,8 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			 "%s: invalid state %s\n", __func__,
+			 rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -500,7 +504,8 @@ enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *
 	state = sci_rnc->sm.current_state_id;
 	if (state != SCI_RNC_READY) {
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			 "%s: invalid state %s\n", __func__,
+			 rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 
@@ -571,7 +576,8 @@ enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *s
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			 "%s: invalid state %s\n", __func__,
+			 rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }
@@ -590,15 +596,15 @@ enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context
 	case SCI_RNC_TX_RX_SUSPENDED:
 	case SCI_RNC_AWAIT_SUSPENSION:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			 "%s: invalid state %s\n", __func__,
+			 rnc_state_name(state));
 		return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
 	default:
-		break;
+		dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
+			"%s: invalid state %s\n", __func__,
+			rnc_state_name(state));
+		return SCI_FAILURE_INVALID_STATE;
 	}
-	dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-		"%s: requested to start IO while still resuming, %d\n",
-		__func__, state);
-	return SCI_FAILURE_INVALID_STATE;
 }
 
 enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc,
@@ -618,7 +624,8 @@ enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_contex
 		return SCI_SUCCESS;
 	default:
 		dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)),
-			 "%s: invalid state %d\n", __func__, state);
+			"%s: invalid state %s\n", __func__,
+			rnc_state_name(state));
 		return SCI_FAILURE_INVALID_STATE;
 	}
 }


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

* [isci PATCH v2 02/18] isci: kill ->is_direct_attached
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
  2012-03-11  7:27 ` [isci PATCH v2 01/18] isci: improve 'invalid state' warnings Dan Williams
@ 2012-03-11  7:27 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 03/18] isci: kill sci_phy_protocol and sci_request_protocol Dan Williams
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:27 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

domain_device ->parent conveys the same information.

Occurrences of ->is_direct_attached appear next to incomplete open-coded
versions of dev_is_sata(), clean those up as well.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.h                |    4 ++--
 drivers/scsi/isci/remote_device.c       |   29 +++++------------------------
 drivers/scsi/isci/remote_device.h       |    1 -
 drivers/scsi/isci/remote_node_context.c |   27 ++++++++-------------------
 drivers/scsi/isci/request.c             |    5 ++---
 5 files changed, 17 insertions(+), 49 deletions(-)

diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index adbad69..a9679ee 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -55,6 +55,7 @@
 #ifndef _SCI_HOST_H_
 #define _SCI_HOST_H_
 
+#include <scsi/sas_ata.h>
 #include "remote_device.h"
 #include "phy.h"
 #include "isci.h"
@@ -378,8 +379,7 @@ static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
 {
 	struct domain_device *dev = idev->domain_dev;
 
-	if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
-	    !idev->is_direct_attached)
+	if (dev_is_sata(dev) && dev->parent)
 		return SCU_STP_REMOTE_NODE_COUNT;
 	return SCU_SSP_REMOTE_NODE_COUNT;
 }
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 8f501b0..71f5090 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -1113,33 +1113,20 @@ static enum sci_status sci_remote_device_da_construct(struct isci_port *iport,
 {
 	enum sci_status status;
 	struct sci_port_properties properties;
-	struct domain_device *dev = idev->domain_dev;
 
 	sci_remote_device_construct(iport, idev);
 
-	/*
-	 * This information is request to determine how many remote node context
-	 * entries will be needed to store the remote node.
-	 */
-	idev->is_direct_attached = true;
-
 	sci_port_get_properties(iport, &properties);
 	/* Get accurate port width from port's phy mask for a DA device. */
 	idev->device_port_width = hweight32(properties.phy_mask);
 
 	status = sci_controller_allocate_remote_node_context(iport->owning_controller,
-								  idev,
-								  &idev->rnc.remote_node_index);
+							     idev,
+							     &idev->rnc.remote_node_index);
 
 	if (status != SCI_SUCCESS)
 		return status;
 
-	if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV ||
-	    (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev))
-		/* pass */;
-	else
-		return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
-
 	idev->connection_rate = sci_port_get_max_allowed_speed(iport);
 
 	return SCI_SUCCESS;
@@ -1171,19 +1158,13 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
 	if (status != SCI_SUCCESS)
 		return status;
 
-	if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV ||
-	    (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev))
-		/* pass */;
-	else
-		return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
-
-	/*
-	 * For SAS-2 the physical link rate is actually a logical link
+	/* For SAS-2 the physical link rate is actually a logical link
 	 * rate that incorporates multiplexing.  The SCU doesn't
 	 * incorporate multiplexing and for the purposes of the
 	 * connection the logical link rate is that same as the
 	 * physical.  Furthermore, the SAS-2 and SAS-1.1 fields overlay
-	 * one another, so this code works for both situations. */
+	 * one another, so this code works for both situations.
+	 */
 	idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport),
 					 dev->linkrate);
 
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index 58637ee..4a67ff0 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -94,7 +94,6 @@ struct isci_remote_device {
 	struct sci_base_state_machine sm;
 	u32 device_port_width;
 	enum sas_linkrate connection_rate;
-	bool is_direct_attached;
 	struct isci_port *owning_port;
 	struct sci_remote_node_context rnc;
 	/* XXX unify with device reference counting and delete */
diff --git a/drivers/scsi/isci/remote_node_context.c b/drivers/scsi/isci/remote_node_context.c
index 994ec0c..8ce5a35 100644
--- a/drivers/scsi/isci/remote_node_context.c
+++ b/drivers/scsi/isci/remote_node_context.c
@@ -131,7 +131,7 @@ static void sci_remote_node_context_construct_buffer(struct sci_remote_node_cont
 
 	rnc->ssp.arbitration_wait_time = 0;
 
-	if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
+	if (dev_is_sata(dev)) {
 		rnc->ssp.connection_occupancy_timeout =
 			ihost->user_parameters.stp_max_occupancy_timeout;
 		rnc->ssp.connection_inactivity_timeout =
@@ -219,13 +219,12 @@ static void sci_remote_node_context_validate_context_buffer(struct sci_remote_no
 
 	rnc_buffer->ssp.is_valid = true;
 
-	if (!idev->is_direct_attached &&
-	    (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) {
+	if (dev_is_sata(dev) && dev->parent) {
 		sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96);
 	} else {
 		sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32);
 
-		if (idev->is_direct_attached)
+		if (!dev->parent)
 			sci_port_setup_transports(idev->owning_port,
 						  sci_rnc->remote_node_index);
 	}
@@ -287,10 +286,8 @@ static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_m
 	 * resume because of a target reset we also need to update
 	 * the STPTLDARNI register with the RNi of the device
 	 */
-	if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
-	    idev->is_direct_attached)
-		sci_port_setup_transports(idev->owning_port,
-					       rnc->remote_node_index);
+	if (dev_is_sata(dev) && !dev->parent)
+		sci_port_setup_transports(idev->owning_port, rnc->remote_node_index);
 
 	sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME);
 }
@@ -553,18 +550,10 @@ 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);
 
-		/* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */
-		if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev))
+		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);
-		else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
-			if (idev->is_direct_attached) {
-				/* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */
-				sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING);
-			} else {
-				sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING);
-			}
-		} else
-			return SCI_FAILURE;
 		return SCI_SUCCESS;
 	}
 	case SCI_RNC_TX_RX_SUSPENDED:
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index ab18ee0fe..9a9b59d 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -3193,7 +3193,7 @@ sci_io_request_construct(struct isci_host *ihost,
 
 	if (dev->dev_type == SAS_END_DEV)
 		/* pass */;
-	else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
+	else if (dev_is_sata(dev))
 		memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd));
 	else if (dev_is_expander(dev))
 		/* pass */;
@@ -3215,8 +3215,7 @@ enum sci_status sci_task_request_construct(struct isci_host *ihost,
 	/* Build the common part of the request */
 	sci_general_request_construct(ihost, idev, ireq);
 
-	if (dev->dev_type == SAS_END_DEV ||
-	    dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) {
+	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));
 	} else


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

* [isci PATCH v2 03/18] isci: kill sci_phy_protocol and sci_request_protocol
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
  2012-03-11  7:27 ` [isci PATCH v2 01/18] isci: improve 'invalid state' warnings Dan Williams
  2012-03-11  7:27 ` [isci PATCH v2 02/18] isci: kill ->is_direct_attached Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 04/18] isci: Don't filter BROADCAST CHANGE primitives Dan Williams
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

Holdovers from the initial driver cleanup, replace with enum sas_protocol.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c    |    4 ++--
 drivers/scsi/isci/phy.c     |   12 ++++++------
 drivers/scsi/isci/phy.h     |    9 +--------
 drivers/scsi/isci/port.c    |   14 ++++++--------
 drivers/scsi/isci/request.c |   10 +++++-----
 drivers/scsi/isci/request.h |    9 +--------
 include/scsi/sas.h          |    1 +
 7 files changed, 22 insertions(+), 37 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 3822ffb..83886a2 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1911,7 +1911,7 @@ static void power_control_timeout(unsigned long data)
 		ihost->power_control.phys_granted_power++;
 		sci_phy_consume_power_handler(iphy);
 
-		if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+		if (iphy->protocol == SAS_PROTOCOL_SSP) {
 			u8 j;
 
 			for (j = 0; j < SCI_MAX_PHYS; j++) {
@@ -1985,7 +1985,7 @@ void sci_controller_power_control_queue_insert(struct isci_host *ihost,
 				       sizeof(current_phy->frame_rcvd.iaf.sas_addr));
 
 			if (current_phy->sm.current_state_id == SCI_PHY_READY &&
-			    current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
+			    current_phy->protocol == SAS_PROTOCOL_SSP &&
 			    other == 0) {
 				sci_phy_consume_power_handler(iphy);
 				break;
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index fab3586..c685ab0 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -580,7 +580,7 @@ static void sci_phy_start_sas_link_training(struct isci_phy *iphy)
 
 	sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SAS_SPEED_EN);
 
-	iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS;
+	iphy->protocol = SAS_PROTOCOL_SSP;
 }
 
 static void sci_phy_start_sata_link_training(struct isci_phy *iphy)
@@ -591,7 +591,7 @@ static void sci_phy_start_sata_link_training(struct isci_phy *iphy)
 	 */
 	sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER);
 
-	iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+	iphy->protocol = SAS_PROTOCOL_SATA;
 }
 
 /**
@@ -797,7 +797,7 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 			 */
 			break;
 		case SCU_EVENT_SATA_PHY_DETECTED:
-			iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
+			iphy->protocol = SAS_PROTOCOL_SATA;
 
 			/* We have received the SATA PHY notification change state */
 			sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN);
@@ -1215,7 +1215,7 @@ static void sci_phy_starting_state_enter(struct sci_base_state_machine *sm)
 	scu_link_layer_start_oob(iphy);
 
 	/* We don't know what kind of phy we are going to be just yet */
-	iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+	iphy->protocol = SAS_PROTOCOL_NONE;
 	iphy->bcn_received_while_port_unassigned = false;
 
 	if (iphy->sm.previous_state_id == SCI_PHY_READY)
@@ -1250,7 +1250,7 @@ static void sci_phy_resetting_state_enter(struct sci_base_state_machine *sm)
 	 */
 	sci_port_deactivate_phy(iphy->owning_port, iphy, false);
 
-	if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+	if (iphy->protocol == SAS_PROTOCOL_SSP) {
 		scu_link_layer_tx_hard_reset(iphy);
 	} else {
 		/* The SCU does not need to have a discrete reset state so
@@ -1316,7 +1316,7 @@ void sci_phy_construct(struct isci_phy *iphy,
 	iphy->owning_port = iport;
 	iphy->phy_index = phy_index;
 	iphy->bcn_received_while_port_unassigned = false;
-	iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
+	iphy->protocol = SAS_PROTOCOL_NONE;
 	iphy->link_layer_registers = NULL;
 	iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN;
 
diff --git a/drivers/scsi/isci/phy.h b/drivers/scsi/isci/phy.h
index 0e45833..45fecfa 100644
--- a/drivers/scsi/isci/phy.h
+++ b/drivers/scsi/isci/phy.h
@@ -76,13 +76,6 @@
  */
 #define SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT  250
 
-enum sci_phy_protocol {
-	SCIC_SDS_PHY_PROTOCOL_UNKNOWN,
-	SCIC_SDS_PHY_PROTOCOL_SAS,
-	SCIC_SDS_PHY_PROTOCOL_SATA,
-	SCIC_SDS_MAX_PHY_PROTOCOLS
-};
-
 /**
  * isci_phy - hba local phy infrastructure
  * @sm:
@@ -95,7 +88,7 @@ struct isci_phy {
 	struct sci_base_state_machine sm;
 	struct isci_port *owning_port;
 	enum sas_linkrate max_negotiated_speed;
-	enum sci_phy_protocol protocol;
+	enum sas_protocol protocol;
 	u8 phy_index;
 	bool bcn_received_while_port_unassigned;
 	bool is_in_link_training;
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 5fada73..923579f 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -184,7 +184,7 @@ static void isci_port_link_up(struct isci_host *isci_host,
 
 	sci_port_get_properties(iport, &properties);
 
-	if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) {
+	if (iphy->protocol == SAS_PROTOCOL_SATA) {
 		u64 attached_sas_address;
 
 		iphy->sas_phy.oob_mode = SATA_OOB_MODE;
@@ -204,7 +204,7 @@ static void isci_port_link_up(struct isci_host *isci_host,
 
 		memcpy(&iphy->sas_phy.attached_sas_addr,
 		       &attached_sas_address, sizeof(attached_sas_address));
-	} else if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) {
+	} else if (iphy->protocol == SAS_PROTOCOL_SSP) {
 		iphy->sas_phy.oob_mode = SAS_OOB_MODE;
 		iphy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame);
 
@@ -517,7 +517,7 @@ void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_a
 	 */
 	iphy = sci_port_get_a_connected_phy(iport);
 	if (iphy) {
-		if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) {
+		if (iphy->protocol != SAS_PROTOCOL_SATA) {
 			sci_phy_get_attached_sas_address(iphy, sas);
 		} else {
 			sci_phy_get_sas_address(iphy, sas);
@@ -624,7 +624,7 @@ static void sci_port_activate_phy(struct isci_port *iport,
 {
 	struct isci_host *ihost = iport->owning_controller;
 
-	if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME))
+	if (iphy->protocol != SAS_PROTOCOL_SATA && (flags & PF_RESUME))
 		sci_phy_resume(iphy);
 
 	iport->active_phy_mask |= 1 << iphy->phy_index;
@@ -751,12 +751,10 @@ static bool sci_port_is_wide(struct isci_port *iport)
  * wide ports and direct attached phys.  Since there are no wide ported SATA
  * devices this could become an invalid port configuration.
  */
-bool sci_port_link_detected(
-	struct isci_port *iport,
-	struct isci_phy *iphy)
+bool sci_port_link_detected(struct isci_port *iport, struct isci_phy *iphy)
 {
 	if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) &&
-	    (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) {
+	    (iphy->protocol == SAS_PROTOCOL_SATA)) {
 		if (sci_port_is_wide(iport)) {
 			sci_port_invalid_link_up(iport, iphy);
 			return false;
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 9a9b59d..1cda610 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -730,7 +730,7 @@ static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *i
 {
 	struct sas_task *task = isci_request_access_task(ireq);
 
-	ireq->protocol = SCIC_SSP_PROTOCOL;
+	ireq->protocol = SAS_PROTOCOL_SSP;
 
 	scu_ssp_io_request_construct_task_context(ireq,
 						  task->data_dir,
@@ -763,7 +763,7 @@ static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *
 	bool copy = false;
 	struct sas_task *task = isci_request_access_task(ireq);
 
-	ireq->protocol = SCIC_STP_PROTOCOL;
+	ireq->protocol = SAS_PROTOCOL_STP;
 
 	copy = (task->data_dir == DMA_NONE) ? false : true;
 
@@ -1070,7 +1070,7 @@ request_started_state_tc_event(struct isci_request *ireq,
 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS):
 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR):
 	case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR):
-		if (ireq->protocol == SCIC_STP_PROTOCOL) {
+		if (ireq->protocol == SAS_PROTOCOL_STP) {
 			ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >>
 					   SCU_COMPLETION_TL_STATUS_SHIFT;
 			ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED;
@@ -3169,7 +3169,7 @@ sci_general_request_construct(struct isci_host *ihost,
 	sci_init_sm(&ireq->sm, sci_request_state_table, SCI_REQ_INIT);
 
 	ireq->target_device = idev;
-	ireq->protocol = SCIC_NO_PROTOCOL;
+	ireq->protocol = SAS_PROTOCOL_NONE;
 	ireq->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX;
 
 	ireq->sci_status   = SCI_SUCCESS;
@@ -3310,7 +3310,7 @@ sci_io_request_construct_smp(struct device *dev,
 	if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE))
 		return SCI_FAILURE;
 
-	ireq->protocol = SCIC_SMP_PROTOCOL;
+	ireq->protocol = SAS_PROTOCOL_SMP;
 
 	/* byte swap the smp request. */
 
diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h
index 057f237..4961f9f 100644
--- a/drivers/scsi/isci/request.h
+++ b/drivers/scsi/isci/request.h
@@ -77,13 +77,6 @@ enum isci_request_status {
 	dead        = 0x07
 };
 
-enum sci_request_protocol {
-	SCIC_NO_PROTOCOL,
-	SCIC_SMP_PROTOCOL,
-	SCIC_SSP_PROTOCOL,
-	SCIC_STP_PROTOCOL
-}; /* XXX remove me, use sas_task.{dev|task_proto} instead */;
-
 /**
  * isci_stp_request - extra request infrastructure to handle pio/atapi protocol
  * @pio_len - number of bytes requested at PIO setup
@@ -140,7 +133,7 @@ struct isci_request {
 	struct isci_host *owning_controller;
 	struct isci_remote_device *target_device;
 	u16 io_tag;
-	enum sci_request_protocol protocol;
+	enum sas_protocol protocol;
 	u32 scu_status; /* hardware result */
 	u32 sci_status; /* upper layer disposition */
 	u32 post_context;
diff --git a/include/scsi/sas.h b/include/scsi/sas.h
index a577a83..be3eb0b 100644
--- a/include/scsi/sas.h
+++ b/include/scsi/sas.h
@@ -103,6 +103,7 @@ enum sas_dev_type {
 };
 
 enum sas_protocol {
+	SAS_PROTOCOL_NONE		= 0,
 	SAS_PROTOCOL_SATA		= 0x01,
 	SAS_PROTOCOL_SMP		= 0x02,
 	SAS_PROTOCOL_STP		= 0x04,


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

* [isci PATCH v2 04/18] isci: Don't filter BROADCAST CHANGE primitives
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (2 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 03/18] isci: kill sci_phy_protocol and sci_request_protocol Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 05/18] isci: kill ->status, and ->state_lock in isci_host Dan Williams
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: Tom Jackson, linux-ide

From: Tom Jackson <thomas.p.jackson@intel.com>

Per the SAS spec, several types of BROADCAST CHANGE primitives
must cause re-discovery of the originating expander.
Only the standard BROADCAST CHANGE primitive was being
sent to the LIBSAS layer.  The other BC primitives have been
added to the sci_phy_event_handler()

Signed-off-by: Tom Jackson <thomas.p.jackson@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/phy.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index c685ab0..474330f 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -875,12 +875,19 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
 		case SCU_EVENT_BROADCAST_CHANGE:
+		case SCU_EVENT_BROADCAST_SES:
+		case SCU_EVENT_BROADCAST_RESERVED0:
+		case SCU_EVENT_BROADCAST_RESERVED1:
+		case SCU_EVENT_BROADCAST_EXPANDER:
+		case SCU_EVENT_BROADCAST_AEN:
 			/* Broadcast change received. Notify the port. */
 			if (phy_get_non_dummy_port(iphy) != NULL)
 				sci_port_broadcast_change_received(iphy->owning_port, iphy);
 			else
 				iphy->bcn_received_while_port_unassigned = true;
 			break;
+		case SCU_EVENT_BROADCAST_RESERVED3:
+		case SCU_EVENT_BROADCAST_RESERVED4:
 		default:
 			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE_INVALID_STATE;


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

* [isci PATCH v2 05/18] isci: kill ->status, and ->state_lock in isci_host
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (3 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 04/18] isci: Don't filter BROADCAST CHANGE primitives Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 06/18] isci: kill isci_port.domain_dev_list Dan Williams
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

They serve no incremental purpose over the existing sas_ha state.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c |   11 -----------
 drivers/scsi/isci/host.h |   23 -----------------------
 2 files changed, 0 insertions(+), 34 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 83886a2..d647b07 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -642,7 +642,6 @@ static void isci_host_start_complete(struct isci_host *ihost, enum sci_status co
 	if (completion_status != SCI_SUCCESS)
 		dev_info(&ihost->pdev->dev,
 			"controller start timed out, continuing...\n");
-	isci_host_change_state(ihost, isci_ready);
 	clear_bit(IHOST_START_PENDING, &ihost->flags);
 	wake_up(&ihost->eventq);
 }
@@ -657,12 +656,7 @@ int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time)
 
 	sas_drain_work(ha);
 
-	dev_dbg(&ihost->pdev->dev,
-		"%s: ihost->status = %d, time = %ld\n",
-		 __func__, isci_host_get_state(ihost), time);
-
 	return 1;
-
 }
 
 /**
@@ -1054,7 +1048,6 @@ void isci_host_scan_start(struct Scsi_Host *shost)
 
 static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status)
 {
-	isci_host_change_state(ihost, isci_stopped);
 	sci_controller_disable_interrupts(ihost);
 	clear_bit(IHOST_STOP_PENDING, &ihost->flags);
 	wake_up(&ihost->eventq);
@@ -1262,7 +1255,6 @@ void isci_host_deinit(struct isci_host *ihost)
 	for (i = 0; i < isci_gpio_count(ihost); i++)
 		writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
 
-	isci_host_change_state(ihost, isci_stopping);
 	for (i = 0; i < SCI_MAX_PORTS; i++) {
 		struct isci_port *iport = &ihost->ports[i];
 		struct isci_remote_device *idev, *d;
@@ -2494,12 +2486,9 @@ int isci_host_init(struct isci_host *ihost)
 	struct sci_user_parameters sci_user_params;
 	struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
 
-	spin_lock_init(&ihost->state_lock);
 	spin_lock_init(&ihost->scic_lock);
 	init_waitqueue_head(&ihost->eventq);
 
-	isci_host_change_state(ihost, isci_starting);
-
 	status = sci_controller_construct(ihost, scu_base(ihost),
 					  smu_base(ihost));
 
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index a9679ee..81485b4 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -191,9 +191,7 @@ struct isci_host {
 	struct asd_sas_port sas_ports[SCI_MAX_PORTS];
 	struct sas_ha_struct sas_ha;
 
-	spinlock_t state_lock;
 	struct pci_dev *pdev;
-	enum isci_status status;
 	#define IHOST_START_PENDING 0
 	#define IHOST_STOP_PENDING 1
 	unsigned long flags;
@@ -315,27 +313,6 @@ static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
 	     id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
 	     ihost = to_pci_info(pdev)->hosts[++id])
 
-static inline enum isci_status isci_host_get_state(struct isci_host *isci_host)
-{
-	return isci_host->status;
-}
-
-static inline void isci_host_change_state(struct isci_host *isci_host,
-					  enum isci_status status)
-{
-	unsigned long flags;
-
-	dev_dbg(&isci_host->pdev->dev,
-		"%s: isci_host = %p, state = 0x%x",
-		__func__,
-		isci_host,
-		status);
-	spin_lock_irqsave(&isci_host->state_lock, flags);
-	isci_host->status = status;
-	spin_unlock_irqrestore(&isci_host->state_lock, flags);
-
-}
-
 static inline void wait_for_start(struct isci_host *ihost)
 {
 	wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags));


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

* [isci PATCH v2 06/18] isci: kill isci_port.domain_dev_list
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (4 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 05/18] isci: kill ->status, and ->state_lock in isci_host Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 07/18] isci: refactor initialization for S3/S4 Dan Williams
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

Another unused field, and isci_port_init is overkill.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c |    8 ++++++--
 drivers/scsi/isci/port.c |    7 -------
 drivers/scsi/isci/port.h |    6 ------
 3 files changed, 6 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index d647b07..bbec198 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -2557,8 +2557,12 @@ int isci_host_init(struct isci_host *ihost)
 	if (err)
 		return err;
 
-	for (i = 0; i < SCI_MAX_PORTS; i++)
-		isci_port_init(&ihost->ports[i], ihost, i);
+	for (i = 0; i < SCI_MAX_PORTS; i++) {
+		struct isci_port *iport = &ihost->ports[i];
+
+		INIT_LIST_HEAD(&iport->remote_dev_list);
+		iport->isci_host = ihost;
+	}
 
 	for (i = 0; i < SCI_MAX_PHYS; i++)
 		isci_phy_init(&ihost->phys[i], ihost, i);
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 923579f..6ef4bd9 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -1606,13 +1606,6 @@ void sci_port_construct(struct isci_port *iport, u8 index,
 		iport->phy_table[index] = NULL;
 }
 
-void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index)
-{
-	INIT_LIST_HEAD(&iport->remote_dev_list);
-	INIT_LIST_HEAD(&iport->domain_dev_list);
-	iport->isci_host = ihost;
-}
-
 void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy)
 {
 	struct isci_host *ihost = iport->owning_controller;
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index 6b56240..f8bd1e8 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -97,7 +97,6 @@ enum isci_status {
 struct isci_port {
 	struct isci_host *isci_host;
 	struct list_head remote_dev_list;
-	struct list_head domain_dev_list;
 	#define IPORT_RESET_PENDING 0
 	unsigned long state;
 	enum sci_status hard_reset_status;
@@ -273,11 +272,6 @@ void sci_port_get_attached_sas_address(
 void isci_port_formed(struct asd_sas_phy *);
 void isci_port_deformed(struct asd_sas_phy *);
 
-void isci_port_init(
-	struct isci_port *port,
-	struct isci_host *host,
-	int index);
-
 int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
 				 struct isci_phy *iphy);
 int isci_ata_check_ready(struct domain_device *dev);


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

* [isci PATCH v2 07/18] isci: refactor initialization for S3/S4
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (5 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 06/18] isci: kill isci_port.domain_dev_list Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 08/18] isci: fix controller stop Dan Williams
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Ed Nadolski, Artur Wojcik

Based on an original implementation by Ed Nadolski and Artur Wojcik

In preparation for S3/S4 support refactor initialization so that
driver-load and resume-from-suspend can share the common init path of
isci_host_init().  Organize the initialization into objects that are
self-contained to the driver (initialized by isci_host_init) versus
those that have some upward registration (initialized at allocation time
asd_sas_phy, asd_sas_port, dma allocations).  The largest change is
moving the the validation of the oem and module parameters from
isci_host_init() to isci_host_alloc().

The S3/S4 approach being taken is that libsas will be tasked with
remembering the state of the domain and the lldd is free to be
forgetful.  In the case of isci we'll just re-init using a subset of the
normal driver load path.

[clean up some unused / mis-indented function definitions in host.h]

Signed-off-by: Ed Nadolski <edmund.nadolski@intel.com>
Signed-off-by: Artur Wojcik <artur.wojcik@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c                      |  313 +++++--------------------
 drivers/scsi/isci/host.h                      |   71 ++----
 drivers/scsi/isci/init.c                      |  199 +++++++++++++++-
 drivers/scsi/isci/probe_roms.c                |   12 -
 drivers/scsi/isci/probe_roms.h                |    2 
 drivers/scsi/isci/request.c                   |    4 
 drivers/scsi/isci/unsolicited_frame_control.c |   30 +-
 drivers/scsi/isci/unsolicited_frame_control.h |    6 
 8 files changed, 277 insertions(+), 360 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index bbec198..0fe372f 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1074,7 +1074,7 @@ static void sci_controller_completion_handler(struct isci_host *ihost)
  * @data: This parameter specifies the ISCI host object
  *
  */
-static void isci_host_completion_routine(unsigned long data)
+void isci_host_completion_routine(unsigned long data)
 {
 	struct isci_host *ihost = (struct isci_host *)data;
 	struct list_head    completed_request_list;
@@ -1317,29 +1317,6 @@ static void __iomem *smu_base(struct isci_host *isci_host)
 	return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id;
 }
 
-static void isci_user_parameters_get(struct sci_user_parameters *u)
-{
-	int i;
-
-	for (i = 0; i < SCI_MAX_PHYS; i++) {
-		struct sci_phy_user_params *u_phy = &u->phys[i];
-
-		u_phy->max_speed_generation = phy_gen;
-
-		/* we are not exporting these for now */
-		u_phy->align_insertion_frequency = 0x7f;
-		u_phy->in_connection_align_insertion_frequency = 0xff;
-		u_phy->notify_enable_spin_up_insertion_frequency = 0x33;
-	}
-
-	u->stp_inactivity_timeout = stp_inactive_to;
-	u->ssp_inactivity_timeout = ssp_inactive_to;
-	u->stp_max_occupancy_timeout = stp_max_occ_to;
-	u->ssp_max_occupancy_timeout = ssp_max_occ_to;
-	u->no_outbound_task_timeout = no_outbound_task_to;
-	u->max_concurr_spinup = max_concurr_spinup;
-}
-
 static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm)
 {
 	struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
@@ -1648,55 +1625,6 @@ static const struct sci_base_state sci_controller_state_table[] = {
 	[SCIC_FAILED] = {}
 };
 
-static void sci_controller_set_default_config_parameters(struct isci_host *ihost)
-{
-	/* these defaults are overridden by the platform / firmware */
-	u16 index;
-
-	/* Default to APC mode. */
-	ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
-
-	/* Default to APC mode. */
-	ihost->oem_parameters.controller.max_concurr_spin_up = 1;
-
-	/* Default to no SSC operation. */
-	ihost->oem_parameters.controller.do_enable_ssc = false;
-
-	/* Default to short cables on all phys. */
-	ihost->oem_parameters.controller.cable_selection_mask = 0;
-
-	/* Initialize all of the port parameter information to narrow ports. */
-	for (index = 0; index < SCI_MAX_PORTS; index++) {
-		ihost->oem_parameters.ports[index].phy_mask = 0;
-	}
-
-	/* Initialize all of the phy parameter information. */
-	for (index = 0; index < SCI_MAX_PHYS; index++) {
-		/* Default to 3G (i.e. Gen 2). */
-		ihost->user_parameters.phys[index].max_speed_generation =
-			SCIC_SDS_PARM_GEN2_SPEED;
-
-		/* the frequencies cannot be 0 */
-		ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f;
-		ihost->user_parameters.phys[index].in_connection_align_insertion_frequency = 0xff;
-		ihost->user_parameters.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
-
-		/*
-		 * Previous Vitesse based expanders had a arbitration issue that
-		 * is worked around by having the upper 32-bits of SAS address
-		 * with a value greater then the Vitesse company identifier.
-		 * Hence, usage of 0x5FCFFFFF. */
-		ihost->oem_parameters.phys[index].sas_address.low = 0x1 + ihost->id;
-		ihost->oem_parameters.phys[index].sas_address.high = 0x5FCFFFFF;
-	}
-
-	ihost->user_parameters.stp_inactivity_timeout = 5;
-	ihost->user_parameters.ssp_inactivity_timeout = 5;
-	ihost->user_parameters.stp_max_occupancy_timeout = 5;
-	ihost->user_parameters.ssp_max_occupancy_timeout = 20;
-	ihost->user_parameters.no_outbound_task_timeout = 2;
-}
-
 static void controller_timeout(unsigned long data)
 {
 	struct sci_timer *tmr = (struct sci_timer *)data;
@@ -1753,9 +1681,6 @@ static enum sci_status sci_controller_construct(struct isci_host *ihost,
 
 	sci_init_timer(&ihost->timer, controller_timeout);
 
-	/* Initialize the User and OEM parameters to default values. */
-	sci_controller_set_default_config_parameters(ihost);
-
 	return sci_controller_reset(ihost);
 }
 
@@ -1835,27 +1760,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version)
 	return 0;
 }
 
-static enum sci_status sci_oem_parameters_set(struct isci_host *ihost)
-{
-	u32 state = ihost->sm.current_state_id;
-	struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
-
-	if (state == SCIC_RESET ||
-	    state == SCIC_INITIALIZING ||
-	    state == SCIC_INITIALIZED) {
-		u8 oem_version = pci_info->orom ? pci_info->orom->hdr.version :
-			ISCI_ROM_VER_1_0;
-
-		if (sci_oem_parameters_validate(&ihost->oem_parameters,
-						oem_version))
-			return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
-		return SCI_SUCCESS;
-	}
-
-	return SCI_FAILURE_INVALID_STATE;
-}
-
 static u8 max_spin_up(struct isci_host *ihost)
 {
 	if (ihost->user_parameters.max_concurr_spinup)
@@ -2372,96 +2276,77 @@ static enum sci_status sci_controller_initialize(struct isci_host *ihost)
 	return result;
 }
 
-static enum sci_status sci_user_parameters_set(struct isci_host *ihost,
-					       struct sci_user_parameters *sci_parms)
-{
-	u32 state = ihost->sm.current_state_id;
-
-	if (state == SCIC_RESET ||
-	    state == SCIC_INITIALIZING ||
-	    state == SCIC_INITIALIZED) {
-		u16 index;
-
-		/*
-		 * Validate the user parameters.  If they are not legal, then
-		 * return a failure.
-		 */
-		for (index = 0; index < SCI_MAX_PHYS; index++) {
-			struct sci_phy_user_params *user_phy;
-
-			user_phy = &sci_parms->phys[index];
-
-			if (!((user_phy->max_speed_generation <=
-						SCIC_SDS_PARM_MAX_SPEED) &&
-			      (user_phy->max_speed_generation >
-						SCIC_SDS_PARM_NO_SPEED)))
-				return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
-			if (user_phy->in_connection_align_insertion_frequency <
-					3)
-				return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
-			if ((user_phy->in_connection_align_insertion_frequency <
-						3) ||
-			    (user_phy->align_insertion_frequency == 0) ||
-			    (user_phy->
-				notify_enable_spin_up_insertion_frequency ==
-						0))
-				return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-		}
-
-		if ((sci_parms->stp_inactivity_timeout == 0) ||
-		    (sci_parms->ssp_inactivity_timeout == 0) ||
-		    (sci_parms->stp_max_occupancy_timeout == 0) ||
-		    (sci_parms->ssp_max_occupancy_timeout == 0) ||
-		    (sci_parms->no_outbound_task_timeout == 0))
-			return SCI_FAILURE_INVALID_PARAMETER_VALUE;
-
-		memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms));
-
-		return SCI_SUCCESS;
-	}
-
-	return SCI_FAILURE_INVALID_STATE;
-}
-
-static int sci_controller_mem_init(struct isci_host *ihost)
+static int sci_controller_dma_alloc(struct isci_host *ihost)
 {
 	struct device *dev = &ihost->pdev->dev;
-	dma_addr_t dma;
 	size_t size;
-	int err;
+	int i;
+
+	/* detect re-initialization */
+	if (ihost->completion_queue)
+		return 0;
 
 	size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32);
-	ihost->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+	ihost->completion_queue = dmam_alloc_coherent(dev, size, &ihost->cq_dma,
+						      GFP_KERNEL);
 	if (!ihost->completion_queue)
 		return -ENOMEM;
 
-	writel(lower_32_bits(dma), &ihost->smu_registers->completion_queue_lower);
-	writel(upper_32_bits(dma), &ihost->smu_registers->completion_queue_upper);
-
 	size = ihost->remote_node_entries * sizeof(union scu_remote_node_context);
-	ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma,
+	ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &ihost->rnc_dma,
 							       GFP_KERNEL);
+
 	if (!ihost->remote_node_context_table)
 		return -ENOMEM;
 
-	writel(lower_32_bits(dma), &ihost->smu_registers->remote_node_context_lower);
-	writel(upper_32_bits(dma), &ihost->smu_registers->remote_node_context_upper);
-
 	size = ihost->task_context_entries * sizeof(struct scu_task_context),
-	ihost->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+	ihost->task_context_table = dmam_alloc_coherent(dev, size, &ihost->tc_dma,
+							GFP_KERNEL);
 	if (!ihost->task_context_table)
 		return -ENOMEM;
 
-	ihost->task_context_dma = dma;
-	writel(lower_32_bits(dma), &ihost->smu_registers->host_task_table_lower);
-	writel(upper_32_bits(dma), &ihost->smu_registers->host_task_table_upper);
+	size = SCI_UFI_TOTAL_SIZE;
+	ihost->ufi_buf = dmam_alloc_coherent(dev, size, &ihost->ufi_dma, GFP_KERNEL);
+	if (!ihost->ufi_buf)
+		return -ENOMEM;
+
+	for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
+		struct isci_request *ireq;
+		dma_addr_t dma;
+
+		ireq = dmam_alloc_coherent(dev, sizeof(*ireq), &dma, GFP_KERNEL);
+		if (!ireq)
+			return -ENOMEM;
+
+		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;
+	}
+
+	return 0;
+}
+
+static int sci_controller_mem_init(struct isci_host *ihost)
+{
+	int err = sci_controller_dma_alloc(ihost);
 
-	err = sci_unsolicited_frame_control_construct(ihost);
 	if (err)
 		return err;
 
+	writel(lower_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_lower);
+	writel(upper_32_bits(ihost->cq_dma), &ihost->smu_registers->completion_queue_upper);
+
+	writel(lower_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_lower);
+	writel(upper_32_bits(ihost->rnc_dma), &ihost->smu_registers->remote_node_context_upper);
+
+	writel(lower_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_lower);
+	writel(upper_32_bits(ihost->tc_dma), &ihost->smu_registers->host_task_table_upper);
+
+	sci_unsolicited_frame_control_construct(ihost);
+
 	/*
 	 * Inform the silicon as to the location of the UF headers and
 	 * address table.
@@ -2479,19 +2364,20 @@ static int sci_controller_mem_init(struct isci_host *ihost)
 	return 0;
 }
 
+/**
+ * isci_host_init - (re-)initialize hardware and internal (private) state
+ * @ihost: host to init
+ *
+ * Any public facing objects (like asd_sas_port, and asd_sas_phys), or
+ * one-time initialization objects like locks and waitqueues, are
+ * not touched (they are initialized in isci_host_alloc)
+ */
 int isci_host_init(struct isci_host *ihost)
 {
-	int err = 0, i;
+	int i, err;
 	enum sci_status status;
-	struct sci_user_parameters sci_user_params;
-	struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
-
-	spin_lock_init(&ihost->scic_lock);
-	init_waitqueue_head(&ihost->eventq);
-
-	status = sci_controller_construct(ihost, scu_base(ihost),
-					  smu_base(ihost));
 
+	status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost));
 	if (status != SCI_SUCCESS) {
 		dev_err(&ihost->pdev->dev,
 			"%s: sci_controller_construct failed - status = %x\n",
@@ -2500,48 +2386,6 @@ int isci_host_init(struct isci_host *ihost)
 		return -ENODEV;
 	}
 
-	ihost->sas_ha.dev = &ihost->pdev->dev;
-	ihost->sas_ha.lldd_ha = ihost;
-
-	/*
-	 * grab initial values stored in the controller object for OEM and USER
-	 * parameters
-	 */
-	isci_user_parameters_get(&sci_user_params);
-	status = sci_user_parameters_set(ihost, &sci_user_params);
-	if (status != SCI_SUCCESS) {
-		dev_warn(&ihost->pdev->dev,
-			 "%s: sci_user_parameters_set failed\n",
-			 __func__);
-		return -ENODEV;
-	}
-
-	/* grab any OEM parameters specified in orom */
-	if (pci_info->orom) {
-		status = isci_parse_oem_parameters(&ihost->oem_parameters,
-						   pci_info->orom,
-						   ihost->id);
-		if (status != SCI_SUCCESS) {
-			dev_warn(&ihost->pdev->dev,
-				 "parsing firmware oem parameters failed\n");
-			return -EINVAL;
-		}
-	}
-
-	status = sci_oem_parameters_set(ihost);
-	if (status != SCI_SUCCESS) {
-		dev_warn(&ihost->pdev->dev,
-				"%s: sci_oem_parameters_set failed\n",
-				__func__);
-		return -ENODEV;
-	}
-
-	tasklet_init(&ihost->completion_tasklet,
-		     isci_host_completion_routine, (unsigned long)ihost);
-
-	INIT_LIST_HEAD(&ihost->requests_to_complete);
-	INIT_LIST_HEAD(&ihost->requests_to_errorback);
-
 	spin_lock_irq(&ihost->scic_lock);
 	status = sci_controller_initialize(ihost);
 	spin_unlock_irq(&ihost->scic_lock);
@@ -2557,47 +2401,12 @@ int isci_host_init(struct isci_host *ihost)
 	if (err)
 		return err;
 
-	for (i = 0; i < SCI_MAX_PORTS; i++) {
-		struct isci_port *iport = &ihost->ports[i];
-
-		INIT_LIST_HEAD(&iport->remote_dev_list);
-		iport->isci_host = ihost;
-	}
-
-	for (i = 0; i < SCI_MAX_PHYS; i++)
-		isci_phy_init(&ihost->phys[i], ihost, i);
-
 	/* enable sgpio */
 	writel(1, &ihost->scu_registers->peg0.sgpio.interface_control);
 	for (i = 0; i < isci_gpio_count(ihost); i++)
 		writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
 	writel(0, &ihost->scu_registers->peg0.sgpio.vendor_specific_code);
 
-	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);
-	}
-
-	for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) {
-		struct isci_request *ireq;
-		dma_addr_t dma;
-
-		ireq = dmam_alloc_coherent(&ihost->pdev->dev,
-					   sizeof(struct isci_request), &dma,
-					   GFP_KERNEL);
-		if (!ireq)
-			return -ENOMEM;
-
-		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;
-	}
-
 	return 0;
 }
 
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 81485b4..4695162 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -158,13 +158,17 @@ struct isci_host {
 	struct sci_power_control power_control;
 	u8 io_request_sequence[SCI_MAX_IO_REQUESTS];
 	struct scu_task_context *task_context_table;
-	dma_addr_t task_context_dma;
+	dma_addr_t tc_dma;
 	union scu_remote_node_context *remote_node_context_table;
+	dma_addr_t rnc_dma;
 	u32 *completion_queue;
+	dma_addr_t cq_dma;
 	u32 completion_queue_get;
 	u32 logical_port_entries;
 	u32 remote_node_entries;
 	u32 task_context_entries;
+	void *ufi_buf;
+	dma_addr_t ufi_dma;
 	struct sci_unsolicited_frame_control uf_control;
 
 	/* phy startup */
@@ -452,36 +456,17 @@ void sci_controller_free_remote_node_context(
 	struct isci_remote_device *idev,
 	u16 node_id);
 
-struct isci_request *sci_request_by_tag(struct isci_host *ihost,
-					     u16 io_tag);
-
-void sci_controller_power_control_queue_insert(
-	struct isci_host *ihost,
-	struct isci_phy *iphy);
-
-void sci_controller_power_control_queue_remove(
-	struct isci_host *ihost,
-	struct isci_phy *iphy);
-
-void sci_controller_link_up(
-	struct isci_host *ihost,
-	struct isci_port *iport,
-	struct isci_phy *iphy);
-
-void sci_controller_link_down(
-	struct isci_host *ihost,
-	struct isci_port *iport,
-	struct isci_phy *iphy);
-
-void sci_controller_remote_device_stopped(
-	struct isci_host *ihost,
-	struct isci_remote_device *idev);
-
-void sci_controller_copy_task_context(
-	struct isci_host *ihost,
-	struct isci_request *ireq);
-
-void sci_controller_register_setup(struct isci_host *ihost);
+struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag);
+void sci_controller_power_control_queue_insert(struct isci_host *ihost,
+					       struct isci_phy *iphy);
+void sci_controller_power_control_queue_remove(struct isci_host *ihost,
+					       struct isci_phy *iphy);
+void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport,
+			    struct isci_phy *iphy);
+void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport,
+			      struct isci_phy *iphy);
+void sci_controller_remote_device_stopped(struct isci_host *ihost,
+					  struct isci_remote_device *idev);
 
 enum sci_status sci_controller_continue_io(struct isci_request *ireq);
 int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
@@ -491,27 +476,9 @@ enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
 void isci_tci_free(struct isci_host *ihost, u16 tci);
 
 int isci_host_init(struct isci_host *);
-
-void isci_host_init_controller_names(
-	struct isci_host *isci_host,
-	unsigned int controller_idx);
-
-void isci_host_deinit(
-	struct isci_host *);
-
-void isci_host_port_link_up(
-	struct isci_host *,
-	struct isci_port *,
-	struct isci_phy *);
-int isci_host_dev_found(struct domain_device *);
-
-void isci_host_remote_device_start_complete(
-	struct isci_host *,
-	struct isci_remote_device *,
-	enum sci_status);
-
-void sci_controller_disable_interrupts(
-	struct isci_host *ihost);
+void isci_host_completion_routine(unsigned long data);
+void isci_host_deinit(struct isci_host *);
+void sci_controller_disable_interrupts(struct isci_host *ihost);
 
 enum sci_status sci_controller_start_io(
 	struct isci_host *ihost,
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 5137db5..eda4385 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -397,38 +397,203 @@ static int isci_setup_interrupts(struct pci_dev *pdev)
 	return err;
 }
 
+static void isci_user_parameters_get(struct sci_user_parameters *u)
+{
+	int i;
+
+	for (i = 0; i < SCI_MAX_PHYS; i++) {
+		struct sci_phy_user_params *u_phy = &u->phys[i];
+
+		u_phy->max_speed_generation = phy_gen;
+
+		/* we are not exporting these for now */
+		u_phy->align_insertion_frequency = 0x7f;
+		u_phy->in_connection_align_insertion_frequency = 0xff;
+		u_phy->notify_enable_spin_up_insertion_frequency = 0x33;
+	}
+
+	u->stp_inactivity_timeout = stp_inactive_to;
+	u->ssp_inactivity_timeout = ssp_inactive_to;
+	u->stp_max_occupancy_timeout = stp_max_occ_to;
+	u->ssp_max_occupancy_timeout = ssp_max_occ_to;
+	u->no_outbound_task_timeout = no_outbound_task_to;
+	u->max_concurr_spinup = max_concurr_spinup;
+}
+
+static enum sci_status sci_user_parameters_set(struct isci_host *ihost,
+					       struct sci_user_parameters *sci_parms)
+{
+	u16 index;
+
+	/*
+	 * Validate the user parameters.  If they are not legal, then
+	 * return a failure.
+	 */
+	for (index = 0; index < SCI_MAX_PHYS; index++) {
+		struct sci_phy_user_params *u;
+
+		u = &sci_parms->phys[index];
+
+		if (!((u->max_speed_generation <= SCIC_SDS_PARM_MAX_SPEED) &&
+		      (u->max_speed_generation > SCIC_SDS_PARM_NO_SPEED)))
+			return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+		if (u->in_connection_align_insertion_frequency < 3)
+			return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+		if ((u->in_connection_align_insertion_frequency < 3) ||
+		    (u->align_insertion_frequency == 0) ||
+		    (u->notify_enable_spin_up_insertion_frequency == 0))
+			return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+	}
+
+	if ((sci_parms->stp_inactivity_timeout == 0) ||
+	    (sci_parms->ssp_inactivity_timeout == 0) ||
+	    (sci_parms->stp_max_occupancy_timeout == 0) ||
+	    (sci_parms->ssp_max_occupancy_timeout == 0) ||
+	    (sci_parms->no_outbound_task_timeout == 0))
+		return SCI_FAILURE_INVALID_PARAMETER_VALUE;
+
+	memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms));
+
+	return SCI_SUCCESS;
+}
+
+static void sci_oem_defaults(struct isci_host *ihost)
+{
+	/* these defaults are overridden by the platform / firmware */
+	struct sci_user_parameters *user = &ihost->user_parameters;
+	struct sci_oem_params *oem = &ihost->oem_parameters;
+	int i;
+
+	/* Default to APC mode. */
+	oem->controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
+
+	/* Default to APC mode. */
+	oem->controller.max_concurr_spin_up = 1;
+
+	/* Default to no SSC operation. */
+	oem->controller.do_enable_ssc = false;
+
+	/* Default to short cables on all phys. */
+	oem->controller.cable_selection_mask = 0;
+
+	/* Initialize all of the port parameter information to narrow ports. */
+	for (i = 0; i < SCI_MAX_PORTS; i++)
+		oem->ports[i].phy_mask = 0;
+
+	/* Initialize all of the phy parameter information. */
+	for (i = 0; i < SCI_MAX_PHYS; i++) {
+		/* Default to 3G (i.e. Gen 2). */
+		user->phys[i].max_speed_generation = SCIC_SDS_PARM_GEN2_SPEED;
+
+		/* the frequencies cannot be 0 */
+		user->phys[i].align_insertion_frequency = 0x7f;
+		user->phys[i].in_connection_align_insertion_frequency = 0xff;
+		user->phys[i].notify_enable_spin_up_insertion_frequency = 0x33;
+
+		/* Previous Vitesse based expanders had a arbitration issue that
+		 * is worked around by having the upper 32-bits of SAS address
+		 * with a value greater then the Vitesse company identifier.
+		 * Hence, usage of 0x5FCFFFFF.
+		 */
+		oem->phys[i].sas_address.low = 0x1 + ihost->id;
+		oem->phys[i].sas_address.high = 0x5FCFFFFF;
+	}
+
+	user->stp_inactivity_timeout = 5;
+	user->ssp_inactivity_timeout = 5;
+	user->stp_max_occupancy_timeout = 5;
+	user->ssp_max_occupancy_timeout = 20;
+	user->no_outbound_task_timeout = 2;
+}
+
 static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
 {
-	struct isci_host *isci_host;
+	struct isci_orom *orom = to_pci_info(pdev)->orom;
+	struct sci_user_parameters sci_user_params;
+	u8 oem_version = ISCI_ROM_VER_1_0;
+	struct isci_host *ihost;
 	struct Scsi_Host *shost;
-	int err;
+	int err, i;
 
-	isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
-	if (!isci_host)
+	ihost = devm_kzalloc(&pdev->dev, sizeof(*ihost), GFP_KERNEL);
+	if (!ihost)
+		return NULL;
+
+	ihost->pdev = pdev;
+	ihost->id = id;
+	spin_lock_init(&ihost->scic_lock);
+	init_waitqueue_head(&ihost->eventq);
+	ihost->sas_ha.dev = &ihost->pdev->dev;
+	ihost->sas_ha.lldd_ha = ihost;
+	tasklet_init(&ihost->completion_tasklet,
+		     isci_host_completion_routine, (unsigned long)ihost);
+
+	/* validate module parameters */
+	/* TODO: kill struct sci_user_parameters and reference directly */
+	sci_oem_defaults(ihost);
+	isci_user_parameters_get(&sci_user_params);
+	if (sci_user_parameters_set(ihost, &sci_user_params)) {
+		dev_warn(&pdev->dev,
+			 "%s: sci_user_parameters_set failed\n", __func__);
+		return NULL;
+	}
+
+	/* sanity check platform (or 'firmware') oem parameters */
+	if (orom) {
+		if (id < 0 || id >= SCI_MAX_CONTROLLERS || id > orom->hdr.num_elements) {
+			dev_warn(&pdev->dev, "parsing firmware oem parameters failed\n");
+			return NULL;
+		}
+		ihost->oem_parameters = orom->ctrl[id];
+		oem_version = orom->hdr.version;
+	}
+
+	/* validate oem parameters (platform, firmware, or built-in defaults) */
+	if (sci_oem_parameters_validate(&ihost->oem_parameters, oem_version)) {
+		dev_warn(&pdev->dev, "oem parameter validation failed\n");
 		return NULL;
+	}
+
+	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];
+
+		INIT_LIST_HEAD(&iport->remote_dev_list);
+		iport->isci_host = ihost;
+	}
 
-	isci_host->pdev = pdev;
-	isci_host->id = id;
+	for (i = 0; i < SCI_MAX_PHYS; i++)
+		isci_phy_init(&ihost->phys[i], ihost, i);
+
+	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);
+	}
 
 	shost = scsi_host_alloc(&isci_sht, sizeof(void *));
 	if (!shost)
 		return NULL;
-	isci_host->shost = shost;
+	ihost->shost = shost;
 
 	dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: "
 		 "{%s, %s, %s, %s}\n",
-		 (is_cable_select_overridden() ? "* " : ""), isci_host->id,
-		 lookup_cable_names(decode_cable_selection(isci_host, 3)),
-		 lookup_cable_names(decode_cable_selection(isci_host, 2)),
-		 lookup_cable_names(decode_cable_selection(isci_host, 1)),
-		 lookup_cable_names(decode_cable_selection(isci_host, 0)));
+		 (is_cable_select_overridden() ? "* " : ""), ihost->id,
+		 lookup_cable_names(decode_cable_selection(ihost, 3)),
+		 lookup_cable_names(decode_cable_selection(ihost, 2)),
+		 lookup_cable_names(decode_cable_selection(ihost, 1)),
+		 lookup_cable_names(decode_cable_selection(ihost, 0)));
 
-	err = isci_host_init(isci_host);
+	err = isci_host_init(ihost);
 	if (err)
 		goto err_shost;
 
-	SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
-	isci_host->sas_ha.core.shost = shost;
+	SHOST_TO_SAS_HA(shost) = &ihost->sas_ha;
+	ihost->sas_ha.core.shost = shost;
 	shost->transportt = isci_transport_template;
 
 	shost->max_id = ~0;
@@ -439,11 +604,11 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
 	if (err)
 		goto err_shost;
 
-	err = isci_register_sas_ha(isci_host);
+	err = isci_register_sas_ha(ihost);
 	if (err)
 		goto err_shost_remove;
 
-	return isci_host;
+	return ihost;
 
  err_shost_remove:
 	scsi_remove_host(shost);
diff --git a/drivers/scsi/isci/probe_roms.c b/drivers/scsi/isci/probe_roms.c
index 9b8117b..4d95654 100644
--- a/drivers/scsi/isci/probe_roms.c
+++ b/drivers/scsi/isci/probe_roms.c
@@ -112,18 +112,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
 	return rom;
 }
 
-enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
-					  struct isci_orom *orom, int scu_index)
-{
-	/* check for valid inputs */
-	if (scu_index < 0 || scu_index >= SCI_MAX_CONTROLLERS ||
-	    scu_index > orom->hdr.num_elements || !oem)
-		return -EINVAL;
-
-	*oem = orom->ctrl[scu_index];
-	return 0;
-}
-
 struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
 {
 	struct isci_orom *orom = NULL, *data;
diff --git a/drivers/scsi/isci/probe_roms.h b/drivers/scsi/isci/probe_roms.h
index bb0e9d4..e08b578 100644
--- a/drivers/scsi/isci/probe_roms.h
+++ b/drivers/scsi/isci/probe_roms.h
@@ -156,8 +156,6 @@ int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version);
 
 struct isci_orom;
 struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
-enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
-					  struct isci_orom *orom, int scu_index);
 struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw);
 struct isci_orom *isci_get_efi_var(struct pci_dev *pdev);
 
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 1cda610..3384ead 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -92,11 +92,11 @@ static dma_addr_t to_sgl_element_pair_dma(struct isci_host *ihost,
 	if (idx == 0) {
 		offset = (void *) &ireq->tc->sgl_pair_ab -
 			 (void *) &ihost->task_context_table[0];
-		return ihost->task_context_dma + offset;
+		return ihost->tc_dma + offset;
 	} else if (idx == 1) {
 		offset = (void *) &ireq->tc->sgl_pair_cd -
 			 (void *) &ihost->task_context_table[0];
-		return ihost->task_context_dma + offset;
+		return ihost->tc_dma + offset;
 	}
 
 	return sci_io_request_get_dma_addr(ireq, &ireq->sg_table[idx - 2]);
diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c
index 16f88ab..04a6d0d 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.c
+++ b/drivers/scsi/isci/unsolicited_frame_control.c
@@ -57,31 +57,19 @@
 #include "unsolicited_frame_control.h"
 #include "registers.h"
 
-int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
+void sci_unsolicited_frame_control_construct(struct isci_host *ihost)
 {
 	struct sci_unsolicited_frame_control *uf_control = &ihost->uf_control;
 	struct sci_unsolicited_frame *uf;
-	u32 buf_len, header_len, i;
-	dma_addr_t dma;
-	size_t size;
-	void *virt;
-
-	/*
-	 * Prepare all of the memory sizes for the UF headers, UF address
-	 * table, and UF buffers themselves.
-	 */
-	buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
-	header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header);
-	size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]);
+	dma_addr_t dma = ihost->ufi_dma;
+	void *virt = ihost->ufi_buf;
+	int i;
 
 	/*
 	 * The Unsolicited Frame buffers are set at the start of the UF
 	 * memory descriptor entry. The headers and address table will be
 	 * placed after the buffers.
 	 */
-	virt = dmam_alloc_coherent(&ihost->pdev->dev, size, &dma, GFP_KERNEL);
-	if (!virt)
-		return -ENOMEM;
 
 	/*
 	 * Program the location of the UF header table into the SCU.
@@ -93,8 +81,8 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
 	 *   headers, since we program the UF address table pointers to
 	 *   NULL.
 	 */
-	uf_control->headers.physical_address = dma + buf_len;
-	uf_control->headers.array = virt + buf_len;
+	uf_control->headers.physical_address = dma + SCI_UFI_BUF_SIZE;
+	uf_control->headers.array = virt + SCI_UFI_BUF_SIZE;
 
 	/*
 	 * Program the location of the UF address table into the SCU.
@@ -103,8 +91,8 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
 	 *   byte boundary already due to above programming headers being on a
 	 *   64-bit boundary and headers are on a 64-bytes in size.
 	 */
-	uf_control->address_table.physical_address = dma + buf_len + header_len;
-	uf_control->address_table.array = virt + buf_len + header_len;
+	uf_control->address_table.physical_address = dma + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE;
+	uf_control->address_table.array = virt + SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE;
 	uf_control->get = 0;
 
 	/*
@@ -135,8 +123,6 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost)
 		virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
 		dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE;
 	}
-
-	return 0;
 }
 
 enum sci_status sci_unsolicited_frame_control_get_header(struct sci_unsolicited_frame_control *uf_control,
diff --git a/drivers/scsi/isci/unsolicited_frame_control.h b/drivers/scsi/isci/unsolicited_frame_control.h
index 75d8966..1bc551e 100644
--- a/drivers/scsi/isci/unsolicited_frame_control.h
+++ b/drivers/scsi/isci/unsolicited_frame_control.h
@@ -257,9 +257,13 @@ struct sci_unsolicited_frame_control {
 
 };
 
+#define SCI_UFI_BUF_SIZE (SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE)
+#define SCI_UFI_HDR_SIZE (SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header))
+#define SCI_UFI_TOTAL_SIZE (SCI_UFI_BUF_SIZE + SCI_UFI_HDR_SIZE + SCU_MAX_UNSOLICITED_FRAMES * sizeof(u64))
+
 struct isci_host;
 
-int sci_unsolicited_frame_control_construct(struct isci_host *ihost);
+void sci_unsolicited_frame_control_construct(struct isci_host *ihost);
 
 enum sci_status sci_unsolicited_frame_control_get_header(
 	struct sci_unsolicited_frame_control *uf_control,


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

* [isci PATCH v2 08/18] isci: fix controller stop
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (6 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 07/18] isci: refactor initialization for S3/S4 Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 09/18] isci: fix 'link-up' events occur after 'start-complete' Dan Williams
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Richard Boyd

1/ notify waiters when controller stop completes (fixes 10 second stall
   unloading the driver)
2/ make sure phy stop is after port and device stop

Cc: Richard Boyd <richard.g.boyd@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c |   99 +++++++++++++++++++++++++---------------------
 drivers/scsi/isci/host.h |    8 ----
 2 files changed, 55 insertions(+), 52 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 0fe372f..95c3da6 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1046,7 +1046,7 @@ void isci_host_scan_start(struct Scsi_Host *shost)
 	spin_unlock_irq(&ihost->scic_lock);
 }
 
-static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status)
+static void isci_host_stop_complete(struct isci_host *ihost)
 {
 	sci_controller_disable_interrupts(ihost);
 	clear_bit(IHOST_STOP_PENDING, &ihost->flags);
@@ -1232,7 +1232,7 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost)
 	switch (ihost->sm.current_state_id) {
 	case SCIC_RESET:
 	case SCIC_READY:
-	case SCIC_STOPPED:
+	case SCIC_STOPPING:
 	case SCIC_FAILED:
 		/*
 		 * The reset operation is not a graceful cleanup, just
@@ -1247,6 +1247,44 @@ static enum sci_status sci_controller_reset(struct isci_host *ihost)
 	}
 }
 
+static enum sci_status sci_controller_stop_phys(struct isci_host *ihost)
+{
+	u32 index;
+	enum sci_status status;
+	enum sci_status phy_status;
+
+	status = SCI_SUCCESS;
+
+	for (index = 0; index < SCI_MAX_PHYS; index++) {
+		phy_status = sci_phy_stop(&ihost->phys[index]);
+
+		if (phy_status != SCI_SUCCESS &&
+		    phy_status != SCI_FAILURE_INVALID_STATE) {
+			status = SCI_FAILURE;
+
+			dev_warn(&ihost->pdev->dev,
+				 "%s: Controller stop operation failed to stop "
+				 "phy %d because of status %d.\n",
+				 __func__,
+				 ihost->phys[index].phy_index, phy_status);
+		}
+	}
+
+	return status;
+}
+
+
+/**
+ * isci_host_deinit - shutdown frame reception and dma
+ * @ihost: host to take down
+ *
+ * This is called in either the driver shutdown or the suspend path.  In
+ * the shutdown case libsas went through port teardown and normal device
+ * removal (i.e. physical links stayed up to service scsi_device removal
+ * commands).  In the suspend case we disable the hardware without
+ * notifying libsas of the link down events since we want libsas to
+ * remember the domain across the suspend/resume cycle
+ */
 void isci_host_deinit(struct isci_host *ihost)
 {
 	int i;
@@ -1255,16 +1293,6 @@ void isci_host_deinit(struct isci_host *ihost)
 	for (i = 0; i < isci_gpio_count(ihost); i++)
 		writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]);
 
-	for (i = 0; i < SCI_MAX_PORTS; i++) {
-		struct isci_port *iport = &ihost->ports[i];
-		struct isci_remote_device *idev, *d;
-
-		list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) {
-			if (test_bit(IDEV_ALLOCATED, &idev->flags))
-				isci_remote_device_stop(ihost, idev);
-		}
-	}
-
 	set_bit(IHOST_STOP_PENDING, &ihost->flags);
 
 	spin_lock_irq(&ihost->scic_lock);
@@ -1273,6 +1301,13 @@ void isci_host_deinit(struct isci_host *ihost)
 
 	wait_for_stop(ihost);
 
+	/* phy stop is after controller stop to allow port and device to
+	 * go idle before shutting down the phys, but the expectation is
+	 * that i/o has been shut off well before we reach this
+	 * function.
+	 */
+	sci_controller_stop_phys(ihost);
+
 	/* disable sgpio: where the above wait should give time for the
 	 * enclosure to sample the gpios going inactive
 	 */
@@ -1476,32 +1511,6 @@ static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm)
 	sci_controller_set_interrupt_coalescence(ihost, 0, 0);
 }
 
-static enum sci_status sci_controller_stop_phys(struct isci_host *ihost)
-{
-	u32 index;
-	enum sci_status status;
-	enum sci_status phy_status;
-
-	status = SCI_SUCCESS;
-
-	for (index = 0; index < SCI_MAX_PHYS; index++) {
-		phy_status = sci_phy_stop(&ihost->phys[index]);
-
-		if (phy_status != SCI_SUCCESS &&
-		    phy_status != SCI_FAILURE_INVALID_STATE) {
-			status = SCI_FAILURE;
-
-			dev_warn(&ihost->pdev->dev,
-				 "%s: Controller stop operation failed to stop "
-				 "phy %d because of status %d.\n",
-				 __func__,
-				 ihost->phys[index].phy_index, phy_status);
-		}
-	}
-
-	return status;
-}
-
 static enum sci_status sci_controller_stop_ports(struct isci_host *ihost)
 {
 	u32 index;
@@ -1561,10 +1570,11 @@ static void sci_controller_stopping_state_enter(struct sci_base_state_machine *s
 {
 	struct isci_host *ihost = container_of(sm, typeof(*ihost), sm);
 
-	/* Stop all of the components for this controller */
-	sci_controller_stop_phys(ihost);
-	sci_controller_stop_ports(ihost);
 	sci_controller_stop_devices(ihost);
+	sci_controller_stop_ports(ihost);
+
+	if (!sci_controller_has_remote_devices_stopping(ihost))
+		isci_host_stop_complete(ihost);
 }
 
 static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm)
@@ -1621,7 +1631,6 @@ static const struct sci_base_state sci_controller_state_table[] = {
 		.enter_state = sci_controller_stopping_state_enter,
 		.exit_state = sci_controller_stopping_state_exit,
 	},
-	[SCIC_STOPPED] = {},
 	[SCIC_FAILED] = {}
 };
 
@@ -1641,7 +1650,7 @@ static void controller_timeout(unsigned long data)
 		sci_controller_transition_to_ready(ihost, SCI_FAILURE_TIMEOUT);
 	else if (sm->current_state_id == SCIC_STOPPING) {
 		sci_change_state(sm, SCIC_FAILED);
-		isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT);
+		isci_host_stop_complete(ihost);
 	} else	/* / @todo Now what do we want to do in this case? */
 		dev_err(&ihost->pdev->dev,
 			"%s: Controller timer fired when controller was not "
@@ -2452,7 +2461,7 @@ void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport,
 	}
 }
 
-static bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost)
+bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost)
 {
 	u32 index;
 
@@ -2478,7 +2487,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost,
 	}
 
 	if (!sci_controller_has_remote_devices_stopping(ihost))
-		sci_change_state(&ihost->sm, SCIC_STOPPED);
+		isci_host_stop_complete(ihost);
 }
 
 void sci_controller_post_request(struct isci_host *ihost, u32 request)
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 4695162..a89c0e3 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -277,13 +277,6 @@ enum sci_controller_states {
 	SCIC_STOPPING,
 
 	/**
-	 * This state indicates that the controller has successfully been stopped.
-	 * In this state no new IO operations are permitted.
-	 * This state is entered from the STOPPING state.
-	 */
-	SCIC_STOPPED,
-
-	/**
 	 * This state indicates that the controller could not successfully be
 	 * initialized.  In this state no new IO operations are permitted.
 	 * This state is entered from the INITIALIZING state.
@@ -479,6 +472,7 @@ int isci_host_init(struct isci_host *);
 void isci_host_completion_routine(unsigned long data);
 void isci_host_deinit(struct isci_host *);
 void sci_controller_disable_interrupts(struct isci_host *ihost);
+bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost);
 
 enum sci_status sci_controller_start_io(
 	struct isci_host *ihost,


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

* [isci PATCH v2 09/18] isci: fix 'link-up' events occur after 'start-complete'
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (7 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 08/18] isci: fix controller stop Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 10/18] isci: fix interrupt disable Dan Williams
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, stable, Richard Boyd

The call to wait_for_start() is meant to ensure that all links have been
given a chance to come up before letting the kernel proceed with
probing.  However, the implementation is not correctly syncing with the
port configuration agent.  In the MPC case the ports are hard-coded, in
the APC case we need to wait for the port-configuration to form ports
from the started phys.

Towards that end increase the timeout for the APC agent to form ports,
and delay start complete until all phys are out of link-training.

Cc: <stable@vger.kernel.org>
Cc: Richard Boyd <richard.g.boyd@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c        |   67 +++++++++++++++++++++------------------
 drivers/scsi/isci/host.h        |    3 ++
 drivers/scsi/isci/port_config.c |   18 ++++++----
 3 files changed, 50 insertions(+), 38 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 95c3da6..577a836 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -816,7 +816,7 @@ static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host *
 	       &ihost->scu_registers->sdma.unsolicited_frame_put_pointer);
 }
 
-static void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status)
+void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status)
 {
 	if (ihost->sm.current_state_id == SCIC_STARTING) {
 		/*
@@ -843,6 +843,7 @@ static bool is_phy_starting(struct isci_phy *iphy)
 	case SCI_PHY_SUB_AWAIT_SATA_POWER:
 	case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
 	case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN:
+	case SCI_PHY_SUB_AWAIT_OSSP_EN:
 	case SCI_PHY_SUB_AWAIT_SIG_FIS_UF:
 	case SCI_PHY_SUB_FINAL:
 		return true;
@@ -851,6 +852,39 @@ static bool is_phy_starting(struct isci_phy *iphy)
 	}
 }
 
+bool is_controller_start_complete(struct isci_host *ihost)
+{
+	int i;
+
+	for (i = 0; i < SCI_MAX_PHYS; i++) {
+		struct isci_phy *iphy = &ihost->phys[i];
+		u32 state = iphy->sm.current_state_id;
+
+		/* in apc mode we need to check every phy, in
+		 * mpc mode we only need to check phys that have
+		 * been configured into a port
+		 */
+		if (is_port_config_apc(ihost))
+			/* pass */;
+		else if (!phy_get_non_dummy_port(iphy))
+			continue;
+
+		/* The controller start operation is complete iff:
+		 * - all links have been given an opportunity to start
+		 * - have no indication of a connected device
+		 * - have an indication of a connected device and it has
+		 *   finished the link training process.
+		 */
+		if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
+		    (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
+		    (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
+		    (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask))
+			return false;
+	}
+
+	return true;
+}
+
 /**
  * sci_controller_start_next_phy - start phy
  * @scic: controller
@@ -871,36 +905,7 @@ static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost)
 		return status;
 
 	if (ihost->next_phy_to_start >= SCI_MAX_PHYS) {
-		bool is_controller_start_complete = true;
-		u32 state;
-		u8 index;
-
-		for (index = 0; index < SCI_MAX_PHYS; index++) {
-			iphy = &ihost->phys[index];
-			state = iphy->sm.current_state_id;
-
-			if (!phy_get_non_dummy_port(iphy))
-				continue;
-
-			/* The controller start operation is complete iff:
-			 * - all links have been given an opportunity to start
-			 * - have no indication of a connected device
-			 * - have an indication of a connected device and it has
-			 *   finished the link training process.
-			 */
-			if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) ||
-			    (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) ||
-			    (iphy->is_in_link_training == true && is_phy_starting(iphy)) ||
-			    (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) {
-				is_controller_start_complete = false;
-				break;
-			}
-		}
-
-		/*
-		 * The controller has successfully finished the start process.
-		 * Inform the SCI Core user and transition to the READY state. */
-		if (is_controller_start_complete == true) {
+		if (is_controller_start_complete(ihost)) {
 			sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
 			sci_del_timer(&ihost->phy_timer);
 			ihost->phy_startup_timer_pending = false;
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index a89c0e3..9dc910b 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -109,6 +109,8 @@ struct sci_port_configuration_agent;
 typedef void (*port_config_fn)(struct isci_host *,
 			       struct sci_port_configuration_agent *,
 			       struct isci_port *, struct isci_phy *);
+bool is_port_config_apc(struct isci_host *ihost);
+bool is_controller_start_complete(struct isci_host *ihost);
 
 struct sci_port_configuration_agent {
 	u16 phy_configured_mask;
@@ -473,6 +475,7 @@ void isci_host_completion_routine(unsigned long data);
 void isci_host_deinit(struct isci_host *);
 void sci_controller_disable_interrupts(struct isci_host *ihost);
 bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost);
+void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status);
 
 enum sci_status sci_controller_start_io(
 	struct isci_host *ihost,
diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c
index 6d1e954..cd962da 100644
--- a/drivers/scsi/isci/port_config.c
+++ b/drivers/scsi/isci/port_config.c
@@ -57,7 +57,7 @@
 
 #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT    (10)
 #define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT    (10)
-#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION  (250)
+#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION  (1000)
 
 enum SCIC_SDS_APC_ACTIVITY {
 	SCIC_SDS_APC_SKIP_PHY,
@@ -472,13 +472,9 @@ sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
  * down event or a link up event where we can not yet tell to which a phy
  * belongs.
  */
-static void sci_apc_agent_start_timer(
-	struct sci_port_configuration_agent *port_agent,
-	u32 timeout)
+static void sci_apc_agent_start_timer(struct sci_port_configuration_agent *port_agent,
+				      u32 timeout)
 {
-	if (port_agent->timer_pending)
-		sci_del_timer(&port_agent->timer);
-
 	port_agent->timer_pending = true;
 	sci_mod_timer(&port_agent->timer, timeout);
 }
@@ -697,6 +693,9 @@ static void apc_agent_timeout(unsigned long data)
 						   &ihost->phys[index], false);
 	}
 
+	if (is_controller_start_complete(ihost))
+		sci_controller_transition_to_ready(ihost, SCI_SUCCESS);
+
 done:
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 }
@@ -732,6 +731,11 @@ void sci_port_configuration_agent_construct(
 	}
 }
 
+bool is_port_config_apc(struct isci_host *ihost)
+{
+	return ihost->port_agent.link_up_handler == sci_apc_agent_link_up;
+}
+
 enum sci_status sci_port_configuration_agent_initialize(
 	struct isci_host *ihost,
 	struct sci_port_configuration_agent *port_agent)


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

* [isci PATCH v2 10/18] isci: fix interrupt disable
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (8 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 09/18] isci: fix 'link-up' events occur after 'start-complete' Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 11/18] isci: kill isci_host.shost Dan Williams
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Richard Boyd, Jacek Danecki

There is a (dubious?) lost irq workaround in sci_controller_isr() that
effectively nullifies attempts to disable interrupts.  Until the
workaround can be re-evaluated add some infrastructure to prevent the
interrupt handler from inadvertantly re-enabling interrupts.

The failure mode was interrupts continuing to run after the driver had
been removed and its iomappings torn down.

Reported-by: Jacek Danecki <jacek.danecki@intel.com>
Tested-by: Jacek Danecki <jacek.danecki@intel.com>
[richard: clear remaining interrupts at the end of reset]
Acked-by: Richard Boyd <richard.g.boyd@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c |   39 ++++++++++++++++++++++++++-------------
 drivers/scsi/isci/host.h |    1 +
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 577a836..5832b13 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -192,22 +192,27 @@ static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost)
 
 static bool sci_controller_isr(struct isci_host *ihost)
 {
-	if (sci_controller_completion_queue_has_entries(ihost)) {
+	if (sci_controller_completion_queue_has_entries(ihost))
 		return true;
-	} else {
-		/*
-		 * we have a spurious interrupt it could be that we have already
-		 * emptied the completion queue from a previous interrupt */
-		writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
 
-		/*
-		 * There is a race in the hardware that could cause us not to be notified
-		 * of an interrupt completion if we do not take this step.  We will mask
-		 * then unmask the interrupts so if there is another interrupt pending
-		 * the clearing of the interrupt source we get the next interrupt message. */
+	/* we have a spurious interrupt it could be that we have already
+	 * emptied the completion queue from a previous interrupt
+	 * FIXME: really!?
+	 */
+	writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status);
+
+	/* There is a race in the hardware that could cause us not to be
+	 * notified of an interrupt completion if we do not take this
+	 * step.  We will mask then unmask the interrupts so if there is
+	 * another interrupt pending the clearing of the interrupt
+	 * source we get the next interrupt message.
+	 */
+	spin_lock(&ihost->scic_lock);
+	if (test_bit(IHOST_IRQ_ENABLED, &ihost->flags)) {
 		writel(0xFF000000, &ihost->smu_registers->interrupt_mask);
 		writel(0, &ihost->smu_registers->interrupt_mask);
 	}
+	spin_unlock(&ihost->scic_lock);
 
 	return false;
 }
@@ -698,14 +703,15 @@ static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost)
 
 static void sci_controller_enable_interrupts(struct isci_host *ihost)
 {
-	BUG_ON(ihost->smu_registers == NULL);
+	set_bit(IHOST_IRQ_ENABLED, &ihost->flags);
 	writel(0, &ihost->smu_registers->interrupt_mask);
 }
 
 void sci_controller_disable_interrupts(struct isci_host *ihost)
 {
-	BUG_ON(ihost->smu_registers == NULL);
+	clear_bit(IHOST_IRQ_ENABLED, &ihost->flags);
 	writel(0xffffffff, &ihost->smu_registers->interrupt_mask);
+	readl(&ihost->smu_registers->interrupt_mask); /* flush */
 }
 
 static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost)
@@ -1318,7 +1324,9 @@ void isci_host_deinit(struct isci_host *ihost)
 	 */
 	writel(0, &ihost->scu_registers->peg0.sgpio.interface_control);
 
+	spin_lock_irq(&ihost->scic_lock);
 	sci_controller_reset(ihost);
+	spin_unlock_irq(&ihost->scic_lock);
 
 	/* Cancel any/all outstanding port timers */
 	for (i = 0; i < ihost->logical_port_entries; i++) {
@@ -1605,6 +1613,9 @@ static void sci_controller_reset_hardware(struct isci_host *ihost)
 
 	/* The write to the UFQGP clears the UFQPR */
 	writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer);
+
+	/* clear all interrupts */
+	writel(~SMU_INTERRUPT_STATUS_RESERVED_MASK, &ihost->smu_registers->interrupt_status);
 }
 
 static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm)
@@ -2391,7 +2402,9 @@ int isci_host_init(struct isci_host *ihost)
 	int i, err;
 	enum sci_status status;
 
+	spin_lock_irq(&ihost->scic_lock);
 	status = sci_controller_construct(ihost, scu_base(ihost), smu_base(ihost));
+	spin_unlock_irq(&ihost->scic_lock);
 	if (status != SCI_SUCCESS) {
 		dev_err(&ihost->pdev->dev,
 			"%s: sci_controller_construct failed - status = %x\n",
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 9dc910b..9701c1d 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -200,6 +200,7 @@ struct isci_host {
 	struct pci_dev *pdev;
 	#define IHOST_START_PENDING 0
 	#define IHOST_STOP_PENDING 1
+	#define IHOST_IRQ_ENABLED 2
 	unsigned long flags;
 	wait_queue_head_t eventq;
 	struct Scsi_Host *shost;


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

* [isci PATCH v2 11/18] isci: kill isci_host.shost
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (9 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 10/18] isci: fix interrupt disable Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 12/18] libata: make ata_print_id atomic Dan Williams
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Jacek Danecki

We can retrieve the shost from the sas_ha like the rest of libsas and
drop this out of our local data structure.

Acked-by: Jacek Danecki <jacek.danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.h |    6 +++++-
 drivers/scsi/isci/init.c |   16 +++++++---------
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 9701c1d..7272a0a 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -203,7 +203,6 @@ struct isci_host {
 	#define IHOST_IRQ_ENABLED 2
 	unsigned long flags;
 	wait_queue_head_t eventq;
-	struct Scsi_Host *shost;
 	struct tasklet_struct completion_tasklet;
 	struct list_head requests_to_complete;
 	struct list_head requests_to_errorback;
@@ -308,6 +307,11 @@ static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
 	return pci_get_drvdata(pdev);
 }
 
+static inline struct Scsi_Host *to_shost(struct isci_host *ihost)
+{
+	return ihost->sas_ha.core.shost;
+}
+
 #define for_each_isci_host(id, ihost, pdev) \
 	for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
 	     id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index eda4385..fdae42f 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -271,13 +271,12 @@ static void isci_unregister(struct isci_host *isci_host)
 	if (!isci_host)
 		return;
 
-	shost = isci_host->shost;
-
 	sas_unregister_ha(&isci_host->sas_ha);
 
-	sas_remove_host(isci_host->shost);
-	scsi_remove_host(isci_host->shost);
-	scsi_host_put(isci_host->shost);
+	shost = to_shost(isci_host);
+	sas_remove_host(shost);
+	scsi_remove_host(shost);
+	scsi_host_put(shost);
 }
 
 static int __devinit isci_pci_init(struct pci_dev *pdev)
@@ -578,7 +577,6 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
 	shost = scsi_host_alloc(&isci_sht, sizeof(void *));
 	if (!shost)
 		return NULL;
-	ihost->shost = shost;
 
 	dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: "
 		 "{%s, %s, %s, %s}\n",
@@ -690,11 +688,11 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
 		pci_info->hosts[i] = h;
 
 		/* turn on DIF support */
-		scsi_host_set_prot(h->shost,
+		scsi_host_set_prot(to_shost(h),
 				   SHOST_DIF_TYPE1_PROTECTION |
 				   SHOST_DIF_TYPE2_PROTECTION |
 				   SHOST_DIF_TYPE3_PROTECTION);
-		scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC);
+		scsi_host_set_guard(to_shost(h), SHOST_DIX_GUARD_CRC);
 	}
 
 	err = isci_setup_interrupts(pdev);
@@ -702,7 +700,7 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
 		goto err_host_alloc;
 
 	for_each_isci_host(i, isci_host, pdev)
-		scsi_scan_host(isci_host->shost);
+		scsi_scan_host(to_shost(isci_host));
 
 	return 0;
 


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

* [isci PATCH v2 12/18] libata: make ata_print_id atomic
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (10 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 11/18] isci: kill isci_host.shost Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-04-11  2:21   ` Dan Williams
  2012-04-12 19:58   ` Jeff Garzik
  2012-03-11  7:28 ` [isci PATCH v2 13/18] libsas: continue revalidation Dan Williams
                   ` (5 subsequent siblings)
  17 siblings, 2 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Jacek Danecki

This variable is incremented from multiple contexts (module_init via
libata-lldds and the libsas discovery thread).  Make it atomic to head
off any chance of libsas and libata creating duplicate ids.

Acked-by: Jacek Danecki <jacek.danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/ata/libata-core.c |    4 ++--
 drivers/ata/libata-scsi.c |    4 ++--
 drivers/ata/libata.h      |    2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index ea8444e..bd79c8b 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -97,7 +97,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
 static void ata_dev_xfermask(struct ata_device *dev);
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
-unsigned int ata_print_id = 1;
+atomic_t ata_print_id = ATOMIC_INIT(1);
 
 struct ata_force_param {
 	const char	*name;
@@ -6031,7 +6031,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
 
 	/* give ports names and add SCSI hosts */
 	for (i = 0; i < host->n_ports; i++)
-		host->ports[i]->print_id = ata_print_id++;
+		host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
 
 
 	/* Create associated sysfs transport objects  */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 1ee00c8..93dabdc 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3843,7 +3843,7 @@ int ata_sas_async_port_init(struct ata_port *ap)
 	int rc = ap->ops->port_start(ap);
 
 	if (!rc) {
-		ap->print_id = ata_print_id++;
+		ap->print_id = atomic_inc_return(&ata_print_id);
 		__ata_port_probe(ap);
 	}
 
@@ -3867,7 +3867,7 @@ int ata_sas_port_init(struct ata_port *ap)
 	int rc = ap->ops->port_start(ap);
 
 	if (!rc) {
-		ap->print_id = ata_print_id++;
+		ap->print_id = atomic_inc_return(&ata_print_id);
 		rc = ata_port_probe(ap);
 	}
 
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 2e26fca..9d0fd0b 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -53,7 +53,7 @@ enum {
 	ATA_DNXFER_QUIET	= (1 << 31),
 };
 
-extern unsigned int ata_print_id;
+extern atomic_t ata_print_id;
 extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;


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

* [isci PATCH v2 13/18] libsas: continue revalidation
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (11 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 12/18] libata: make ata_print_id atomic Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:28 ` [isci PATCH v2 14/18] libata: export ata_port suspend/resume infrastructure for sas Dan Williams
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

Continue running revalidation until no more broadcast devices are
discovered.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/libsas/sas_expander.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 05acd9e..dc35128 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -2077,9 +2077,7 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
 	struct domain_device *dev = NULL;
 
 	res = sas_find_bcast_dev(port_dev, &dev);
-	if (res)
-		goto out;
-	if (dev) {
+	while (res == 0 && dev) {
 		struct expander_device *ex = &dev->ex_dev;
 		int i = 0, phy_id;
 
@@ -2091,8 +2089,10 @@ int sas_ex_revalidate_domain(struct domain_device *port_dev)
 			res = sas_rediscover(dev, phy_id);
 			i = phy_id + 1;
 		} while (i < ex->num_phys);
+
+		dev = NULL;
+		res = sas_find_bcast_dev(port_dev, &dev);
 	}
-out:
 	return res;
 }
 


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

* [isci PATCH v2 14/18] libata: export ata_port suspend/resume infrastructure for sas
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (12 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 13/18] libsas: continue revalidation Dan Williams
@ 2012-03-11  7:28 ` Dan Williams
  2012-03-11  7:29 ` [isci PATCH v2 15/18] libsas: drop sata port multiplier infrastructure Dan Williams
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:28 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Jacek Danecki

Reuse ata_port_{suspend|resume}_common for sas.  This path is chosen
over adding coordination between ata-tranport and sas-transport because
libsas wants to revalidate the domain at resume-time at the host level.
It can not validate links have resumed properly until libata has had a
chance to perform its revalidation, and any sane placing of an ata_port
in the sas-transport model would delay it's resumption until after the
host.

Export the common portion of port suspend/resume (bypass pm_runtime),
and allow sas to perform these operations asynchronously (similar to the
libsas async-ata probe implmentation).  Async operation is determined by
having an external, rather than stack based, location for storing the
result of the operation.

Reviewed-by: Jacek Danecki <jacek.danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/ata/libata-core.c |   58 ++++++++++++++++++++++++++++++++++++---------
 include/linux/libata.h    |    2 ++
 2 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index bd79c8b..a13c36d 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5241,16 +5241,20 @@ bool ata_link_offline(struct ata_link *link)
 #ifdef CONFIG_PM
 static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 			       unsigned int action, unsigned int ehi_flags,
-			       int wait)
+			       int *async)
 {
 	struct ata_link *link;
 	unsigned long flags;
-	int rc;
+	int rc = 0;
 
 	/* Previous resume operation might still be in
 	 * progress.  Wait for PM_PENDING to clear.
 	 */
 	if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+		if (async) {
+			*async = -EAGAIN;
+			return 0;
+		}
 		ata_port_wait_eh(ap);
 		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 	}
@@ -5259,10 +5263,10 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	spin_lock_irqsave(ap->lock, flags);
 
 	ap->pm_mesg = mesg;
-	if (wait) {
-		rc = 0;
+	if (async)
+		ap->pm_result = async;
+	else
 		ap->pm_result = &rc;
-	}
 
 	ap->pflags |= ATA_PFLAG_PM_PENDING;
 	ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5275,7 +5279,7 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 	spin_unlock_irqrestore(ap->lock, flags);
 
 	/* wait and check result */
-	if (wait) {
+	if (!async) {
 		ata_port_wait_eh(ap);
 		WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
 	}
@@ -5285,9 +5289,8 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
 
 #define to_ata_port(d) container_of(d, struct ata_port, tdev)
 
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
 {
-	struct ata_port *ap = to_ata_port(dev);
 	unsigned int ehi_flags = ATA_EHI_QUIET;
 	int rc;
 
@@ -5302,10 +5305,17 @@ static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
 	if (mesg.event == PM_EVENT_SUSPEND)
 		ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
 
-	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
+	rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
 	return rc;
 }
 
+static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+{
+	struct ata_port *ap = to_ata_port(dev);
+
+	return __ata_port_suspend_common(ap, mesg, NULL);
+}
+
 static int ata_port_suspend(struct device *dev)
 {
 	if (pm_runtime_suspended(dev))
@@ -5330,16 +5340,22 @@ static int ata_port_poweroff(struct device *dev)
 	return ata_port_suspend_common(dev, PMSG_HIBERNATE);
 }
 
-static int ata_port_resume_common(struct device *dev)
+static int __ata_port_resume_common(struct ata_port *ap, int *async)
 {
-	struct ata_port *ap = to_ata_port(dev);
 	int rc;
 
 	rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
-		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
+		ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
 	return rc;
 }
 
+static int ata_port_resume_common(struct device *dev)
+{
+	struct ata_port *ap = to_ata_port(dev);
+
+	return __ata_port_resume_common(ap, NULL);
+}
+
 static int ata_port_resume(struct device *dev)
 {
 	int rc;
@@ -5372,6 +5388,24 @@ static const struct dev_pm_ops ata_port_pm_ops = {
 	.runtime_idle = ata_port_runtime_idle,
 };
 
+/* sas ports don't participate in pm runtime management of ata_ports,
+ * and need to resume ata devices at the domain level, not the per-port
+ * level. sas suspend/resume is async to allow parallel port recovery
+ * since sas has multiple ata_port instances per Scsi_Host.
+ */
+int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+{
+	return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+
+int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+{
+	return __ata_port_resume_common(ap, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
+
+
 /**
  *	ata_host_suspend - suspend host
  *	@host: host to suspend
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 83ff256..15e1123 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -998,6 +998,8 @@ extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
 extern void ata_sas_port_destroy(struct ata_port *);
 extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
 					   struct ata_port_info *, struct Scsi_Host *);
+extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
+extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
 extern int ata_sas_async_port_init(struct ata_port *);
 extern int ata_sas_port_init(struct ata_port *);
 extern int ata_sas_port_start(struct ata_port *ap);


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

* [isci PATCH v2 15/18] libsas: drop sata port multiplier infrastructure
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (13 preceding siblings ...)
  2012-03-11  7:28 ` [isci PATCH v2 14/18] libata: export ata_port suspend/resume infrastructure for sas Dan Williams
@ 2012-03-11  7:29 ` Dan Williams
  2012-03-11  7:29 ` [isci PATCH v2 16/18] libsas: suspend / resume support Dan Williams
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide

On the way to add a new sata_device field, noticed that libsas is
carrying port multiplier infrastructure that is explicitly disabled by
sas_discover_sata().  The aic94xx touches the unused port_no, so leave
that field in case there was some use for it.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/libsas/sas_discover.c |    6 ------
 include/scsi/libsas.h              |    1 -
 2 files changed, 0 insertions(+), 7 deletions(-)

diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 3c8527d..a98fe6e 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -46,12 +46,6 @@ void sas_init_dev(struct domain_device *dev)
                 INIT_LIST_HEAD(&dev->ex_dev.children);
 		mutex_init(&dev->ex_dev.cmd_mutex);
                 break;
-        case SATA_DEV:
-        case SATA_PM:
-        case SATA_PM_PORT:
-	case SATA_PENDING:
-                INIT_LIST_HEAD(&dev->sata_dev.children);
-                break;
         default:
                 break;
         }
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 1b14d80..ad5229a 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -167,7 +167,6 @@ struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
         u8     port_no;        /* port number, if this is a PM (Port) */
-        struct list_head children; /* PM Ports if this is a PM */
 
 	struct ata_port *ap;
 	struct ata_host ata_host;


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

* [isci PATCH v2 16/18] libsas: suspend / resume support
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (14 preceding siblings ...)
  2012-03-11  7:29 ` [isci PATCH v2 15/18] libsas: drop sata port multiplier infrastructure Dan Williams
@ 2012-03-11  7:29 ` Dan Williams
  2012-03-11  8:06   ` jack_wang
  2012-03-11  7:29 ` [isci PATCH v2 17/18] isci: implement suspend/resume support Dan Williams
  2012-03-11  7:29 ` [isci PATCH v2 18/18] isci: Changes in COMSAS timings enabling ISCI to detect buggy disc drives Dan Williams
  17 siblings, 1 reply; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Jacek Danecki

libsas power management routines to suspend and recover the sas domain
based on a model where the lldd is allowed and expected to be
"forgetful".

sas_suspend_ha - disable event processing allowing the lldd to take down
                 links without concern for causing hotplug events.
                 Regardless of whether the lldd actually posts link down
                 messages libsas notifies the lldd that all
                 domain_devices are gone.

sas_prep_resume_ha - on the way back up before the lldd starts link
                     training clean out any spurious events that were
                     generated on the way down, and re-enable event
                     processing

sas_resume_ha - after the lldd has started and decided that all phys
		have posted link-up events this routine is called to let
		libsas start it's own timeout of any phys that did not
		resume.  After the timeout an lldd can cancel the
                phy teardown by posting a link-up event.

Storage for ex_change_count (u16) and phy_change_count (u8) are changed
to int so they can be set to -1 to indicate 'invalidated'.

Reviewed-by: Jacek Danecki <jacek.danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/libsas/sas_ata.c       |   86 +++++++++++++++++++++++++++++++++
 drivers/scsi/libsas/sas_discover.c  |   68 +++++++++++++++++++++++---
 drivers/scsi/libsas/sas_dump.c      |    1 
 drivers/scsi/libsas/sas_event.c     |    4 +-
 drivers/scsi/libsas/sas_init.c      |   90 +++++++++++++++++++++++++++++++++++
 drivers/scsi/libsas/sas_internal.h  |    2 +
 drivers/scsi/libsas/sas_phy.c       |   21 ++++++++
 drivers/scsi/libsas/sas_port.c      |   52 ++++++++++++++++++++
 drivers/scsi/libsas/sas_scsi_host.c |    2 -
 include/scsi/libsas.h               |   20 ++++++--
 include/scsi/sas_ata.h              |   10 ++++
 11 files changed, 336 insertions(+), 20 deletions(-)

diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index d30a093..b161bdd 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -677,6 +677,92 @@ void sas_probe_sata(struct asd_sas_port *port)
 		if (ata_dev_disabled(sas_to_ata_dev(dev)))
 			sas_fail_probe(dev, __func__, -ENODEV);
 	}
+
+}
+
+static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+{
+	struct domain_device *dev, *n;
+	bool retry = false;
+
+	list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
+		int rc;
+
+		if (!dev_is_sata(dev))
+			continue;
+
+		sas_ata_wait_eh(dev);
+		rc = dev->sata_dev.pm_result;
+		if (rc == -EAGAIN)
+			retry = true;
+		else if (rc) {
+			/* since we don't have a
+			 * ->port_{suspend|resume} routine in our
+			 *  ata_port ops, and no entanglements with
+			 *  acpi, suspend should just be mechanical trip
+			 *  through eh, catch cases where these
+			 *  assumptions are invalidated
+			 */
+			WARN_ONCE(1, "failed %s %s error: %d\n", func,
+				 dev_name(&dev->rphy->dev), rc);
+		}
+
+		/* if libata failed to power manage the device, tear it down */
+		if (ata_dev_disabled(sas_to_ata_dev(dev)))
+			sas_fail_probe(dev, func, -ENODEV);
+	}
+
+	return retry;
+}
+
+void sas_suspend_sata(struct asd_sas_port *port)
+{
+	struct domain_device *dev;
+
+ retry:
+	mutex_lock(&port->ha->disco_mutex);
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		struct sata_device *sata;
+
+		if (!dev_is_sata(dev))
+			continue;
+
+		sata = &dev->sata_dev;
+		if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
+			continue;
+
+		sata->pm_result = -EIO;
+		ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+	}
+	mutex_unlock(&port->ha->disco_mutex);
+
+	if (sas_ata_flush_pm_eh(port, __func__))
+		goto retry;
+}
+
+void sas_resume_sata(struct asd_sas_port *port)
+{
+	struct domain_device *dev;
+
+ retry:
+	mutex_lock(&port->ha->disco_mutex);
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		struct sata_device *sata;
+
+		if (!dev_is_sata(dev))
+			continue;
+
+		sata = &dev->sata_dev;
+		if (sata->ap->pm_mesg.event == PM_EVENT_ON)
+			continue;
+
+		sata->pm_result = -EIO;
+		ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+	}
+	mutex_unlock(&port->ha->disco_mutex);
+
+	if (sas_ata_flush_pm_eh(port, __func__))
+		goto retry;
 }
 
 /**
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index a98fe6e..8b1b4ef 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -171,16 +171,18 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
 	struct Scsi_Host *shost = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(shost->transportt);
 
-	if (i->dft->lldd_dev_found) {
-		res = i->dft->lldd_dev_found(dev);
-		if (res) {
-			printk("sas: driver on pcidev %s cannot handle "
-			       "device %llx, error:%d\n",
-			       dev_name(sas_ha->dev),
-			       SAS_ADDR(dev->sas_addr), res);
-		}
-		kref_get(&dev->kref);
+	if (!i->dft->lldd_dev_found)
+		return 0;
+
+	res = i->dft->lldd_dev_found(dev);
+	if (res) {
+		printk("sas: driver on pcidev %s cannot handle "
+		       "device %llx, error:%d\n",
+		       dev_name(sas_ha->dev),
+		       SAS_ADDR(dev->sas_addr), res);
 	}
+	set_bit(SAS_DEV_FOUND, &dev->state);
+	kref_get(&dev->kref);
 	return res;
 }
 
@@ -191,7 +193,10 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
 	struct Scsi_Host *shost = sas_ha->core.shost;
 	struct sas_internal *i = to_sas_internal(shost->transportt);
 
-	if (i->dft->lldd_dev_gone) {
+	if (!i->dft->lldd_dev_gone)
+		return;
+
+	if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
 		i->dft->lldd_dev_gone(dev);
 		sas_put_device(dev);
 	}
@@ -225,6 +230,47 @@ static void sas_probe_devices(struct work_struct *work)
 	}
 }
 
+static void sas_suspend_devices(struct work_struct *work)
+{
+	struct asd_sas_phy *phy;
+	struct domain_device *dev;
+	struct sas_discovery_event *ev = to_sas_discovery_event(work);
+	struct asd_sas_port *port = ev->port;
+	struct Scsi_Host *shost = port->ha->core.shost;
+	struct sas_internal *si = to_sas_internal(shost->transportt);
+
+	clear_bit(DISCE_SUSPEND, &port->disc.pending);
+
+	sas_suspend_sata(port);
+
+	/* lldd is free to forget the domain_device across the
+	 * suspension, we force the issue here to keep the reference
+	 * counts aligned
+	 */
+	list_for_each_entry(dev, &port->dev_list, dev_list_node)
+		sas_notify_lldd_dev_gone(dev);
+
+	/* we are suspending, so we know events are disabled and
+	 * phy_list is not being mutated
+	 */
+	list_for_each_entry(phy, &port->phy_list, port_phy_el) {
+		if (si->dft->lldd_port_formed)
+			si->dft->lldd_port_deformed(phy);
+		phy->suspended = 1;
+		port->suspended = 1;
+	}
+}
+
+static void sas_resume_devices(struct work_struct *work)
+{
+	struct sas_discovery_event *ev = to_sas_discovery_event(work);
+	struct asd_sas_port *port = ev->port;
+
+	clear_bit(DISCE_RESUME, &port->disc.pending);
+
+	sas_resume_sata(port);
+}
+
 /**
  * sas_discover_end_dev -- discover an end device (SSP, etc)
  * @end: pointer to domain device of interest
@@ -521,6 +567,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
 		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
 		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
 		[DISCE_PROBE] = sas_probe_devices,
+		[DISCE_SUSPEND] = sas_suspend_devices,
+		[DISCE_RESUME] = sas_resume_devices,
 		[DISCE_DESTRUCT] = sas_destruct_devices,
 	};
 
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index fc46093..cd6f99c 100644
--- a/drivers/scsi/libsas/sas_dump.c
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -41,6 +41,7 @@ static const char *sas_phye_str[] = {
 	[1] = "PHYE_OOB_DONE",
 	[2] = "PHYE_OOB_ERROR",
 	[3] = "PHYE_SPINUP_HOLD",
+	[4] = "PHYE_RESUME_TIMEOUT",
 };
 
 void sas_dprint_porte(int phyid, enum port_event pe)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
index 789c4d8..aadbd53 100644
--- a/drivers/scsi/libsas/sas_event.c
+++ b/drivers/scsi/libsas/sas_event.c
@@ -134,7 +134,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
 			&phy->port_events[event].work, ha);
 }
 
-static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
 	struct sas_ha_struct *ha = phy->ha;
 
@@ -159,7 +159,7 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
 
 	sas_ha->notify_ha_event = notify_ha_event;
 	sas_ha->notify_port_event = notify_port_event;
-	sas_ha->notify_phy_event = notify_phy_event;
+	sas_ha->notify_phy_event = sas_notify_phy_event;
 
 	return 0;
 }
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 1bbab3d..29c0910 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -159,7 +159,7 @@ Undo_phys:
 	return error;
 }
 
-int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+static void sas_disable_events(struct sas_ha_struct *sas_ha)
 {
 	/* Set the state to unregistered to avoid further unchained
 	 * events to be queued, and flush any in-progress drainers
@@ -170,7 +170,11 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
 	spin_unlock_irq(&sas_ha->lock);
 	__sas_drain_work(sas_ha);
 	mutex_unlock(&sas_ha->drain_mutex);
+}
 
+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+{
+	sas_disable_events(sas_ha);
 	sas_unregister_ports(sas_ha);
 
 	/* flush unregistration work */
@@ -362,6 +366,90 @@ int sas_set_phy_speed(struct sas_phy *phy,
 	return ret;
 }
 
+void sas_prep_resume_ha(struct sas_ha_struct *ha)
+{
+	int i;
+
+	set_bit(SAS_HA_REGISTERED, &ha->state);
+
+	/* clear out any stale link events/data from the suspension path */
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_phy *phy = ha->sas_phy[i];
+
+		memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+		phy->port_events_pending = 0;
+		phy->phy_events_pending = 0;
+		phy->frame_rcvd_size = 0;
+	}
+}
+EXPORT_SYMBOL(sas_prep_resume_ha);
+
+static int phys_suspended(struct sas_ha_struct *ha)
+{
+	int i, rc = 0;
+
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_phy *phy = ha->sas_phy[i];
+
+		if (phy->suspended)
+			rc++;
+	}
+
+	return rc;
+}
+
+void sas_resume_ha(struct sas_ha_struct *ha)
+{
+	const unsigned long tmo = msecs_to_jiffies(25000);
+	int i;
+
+	/* deform ports on phys that did not resume
+	 * at this point we may be racing the phy coming back (as posted
+	 * by the lldd).  So we post the event and once we are in the
+	 * libsas context check that the phy remains suspended before
+	 * tearing it down.
+	 */
+	i = phys_suspended(ha);
+	if (i)
+		dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
+			 i, i > 1 ? "s" : "");
+	wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_phy *phy = ha->sas_phy[i];
+
+		if (phy->suspended) {
+			dev_warn(&phy->phy->dev, "resume timeout\n");
+			sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT);
+		}
+	}
+
+	/* all phys are back up or timed out, turn on i/o so we can
+	 * flush out disks that did not return
+	 */
+	scsi_unblock_requests(ha->core.shost);
+	sas_drain_work(ha);
+}
+EXPORT_SYMBOL(sas_resume_ha);
+
+void sas_suspend_ha(struct sas_ha_struct *ha)
+{
+	int i;
+
+	sas_disable_events(ha);
+	scsi_block_requests(ha->core.shost);
+	for (i = 0; i < ha->num_phys; i++) {
+		struct asd_sas_port *port = ha->sas_port[i];
+
+		sas_discover_event(port, DISCE_SUSPEND);
+	}
+
+	/* flush suspend events while unregistered */
+	mutex_lock(&ha->drain_mutex);
+	__sas_drain_work(ha);
+	mutex_unlock(&ha->drain_mutex);
+}
+EXPORT_SYMBOL(sas_suspend_ha);
+
 static void sas_phy_release(struct sas_phy *phy)
 {
 	kfree(phy->hostdata);
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 507e4cf..a91028e 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -88,7 +88,9 @@ void sas_notify_lldd_dev_gone(struct domain_device *);
 int sas_smp_phy_control(struct domain_device *dev, int phy_id,
 			enum phy_func phy_func, struct sas_phy_linkrates *);
 int sas_smp_get_phy_events(struct sas_phy *phy);
+int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait);
 
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
 void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
 struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
index 521422e..cdee446 100644
--- a/drivers/scsi/libsas/sas_phy.c
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -94,6 +94,25 @@ static void sas_phye_spinup_hold(struct work_struct *work)
 	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
 }
 
+static void sas_phye_resume_timeout(struct work_struct *work)
+{
+	struct asd_sas_event *ev = to_asd_sas_event(work);
+	struct asd_sas_phy *phy = ev->phy;
+
+	clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
+
+	/* phew, lldd got the phy back in the nick of time */
+	if (!phy->suspended) {
+		dev_info(&phy->phy->dev, "resume timeout cancelled\n");
+		return;
+	}
+
+	phy->error = 0;
+	phy->suspended = 0;
+	sas_deform_port(phy, 1);
+}
+
+
 /* ---------- Phy class registration ---------- */
 
 int sas_register_phys(struct sas_ha_struct *sas_ha)
@@ -105,6 +124,8 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
 		[PHYE_OOB_DONE] = sas_phye_oob_done,
 		[PHYE_OOB_ERROR] = sas_phye_oob_error,
 		[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
+		[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
+
 	};
 
 	static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 1cf7d75..1ac0c8b 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -39,6 +39,49 @@ static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy
 	return true;
 }
 
+static void sas_resume_port(struct asd_sas_phy *phy)
+{
+	struct domain_device *dev;
+	struct asd_sas_port *port = phy->port;
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt);
+
+	if (si->dft->lldd_port_formed)
+		si->dft->lldd_port_formed(phy);
+
+	if (port->suspended)
+		port->suspended = 0;
+	else {
+		/* we only need to handle "link returned" actions once */
+		return;
+	}
+
+	/* if the port came back:
+	 * 1/ presume every device came back
+	 * 2/ force the next revalidation to check all expander phys
+	 */
+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+		int i, rc;
+
+		rc = sas_notify_lldd_dev_found(dev);
+		if (rc) {
+			sas_unregister_dev(port, dev);
+			continue;
+		}
+
+		if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
+			dev->ex_dev.ex_change_count = -1;
+			for (i = 0; i < dev->ex_dev.num_phys; i++) {
+				struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
+
+				phy->phy_change_count = -1;
+			}
+		}
+	}
+
+	sas_discover_event(port, DISCE_RESUME);
+}
+
 /**
  * sas_form_port -- add this phy to a port
  * @phy: the phy of interest
@@ -58,7 +101,14 @@ static void sas_form_port(struct asd_sas_phy *phy)
 	if (port) {
 		if (!phy_is_wideport_member(port, phy))
 			sas_deform_port(phy, 0);
-		else {
+		else if (phy->suspended) {
+			phy->suspended = 0;
+			sas_resume_port(phy);
+
+			/* phy came back, try to cancel the timeout */
+			wake_up(&sas_ha->eh_wait_q);
+			return;
+		} else {
 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
 				    __func__, phy->id, phy->port->id,
 				    phy->port->num_phys);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 50a18a6..07fba82 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -490,7 +490,7 @@ static void sas_wait_eh(struct domain_device *dev)
 }
 EXPORT_SYMBOL(sas_wait_eh);
 
-static int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
+int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
 {
 	struct sas_ha_struct *ha = dev->port->ha;
 	int scheduled = 0, tries = 100;
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index ad5229a..74e17fa 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -79,7 +79,8 @@ enum phy_event {
 	PHYE_OOB_DONE         = 1,
 	PHYE_OOB_ERROR        = 2,
 	PHYE_SPINUP_HOLD      = 3, /* hot plug SATA, no COMWAKE sent */
-	PHY_NUM_EVENTS        = 4,
+	PHYE_RESUME_TIMEOUT   = 4,
+	PHY_NUM_EVENTS        = 5,
 };
 
 enum discover_event {
@@ -87,8 +88,10 @@ enum discover_event {
 	DISCE_REVALIDATE_DOMAIN = 1,
 	DISCE_PORT_GONE         = 2,
 	DISCE_PROBE		= 3,
-	DISCE_DESTRUCT		= 4,
-	DISC_NUM_EVENTS		= 5,
+	DISCE_SUSPEND		= 4,
+	DISCE_RESUME		= 5,
+	DISCE_DESTRUCT		= 6,
+	DISC_NUM_EVENTS		= 7,
 };
 
 /* ---------- Expander Devices ---------- */
@@ -128,7 +131,7 @@ struct ex_phy {
 	u8   attached_sas_addr[SAS_ADDR_SIZE];
 	u8   attached_phy_id;
 
-	u8   phy_change_count;
+	int phy_change_count;
 	enum routing_attribute routing_attr;
 	u8   virtual:1;
 
@@ -141,7 +144,7 @@ struct ex_phy {
 struct expander_device {
 	struct list_head children;
 
-	u16    ex_change_count;
+	int    ex_change_count;
 	u16    max_route_indexes;
 	u8     num_phys;
 
@@ -167,6 +170,7 @@ struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
         u8     port_no;        /* port number, if this is a PM (Port) */
+	int    pm_result;
 
 	struct ata_port *ap;
 	struct ata_host ata_host;
@@ -180,6 +184,7 @@ struct ssp_device {
 
 enum {
 	SAS_DEV_GONE,
+	SAS_DEV_FOUND, /* device notified to lldd */
 	SAS_DEV_DESTROY,
 	SAS_DEV_EH_PENDING,
 	SAS_DEV_LU_RESET,
@@ -271,6 +276,7 @@ struct asd_sas_port {
 	enum   sas_linkrate linkrate;
 
 	struct sas_work work;
+	int suspended;
 
 /* public: */
 	int id;
@@ -319,6 +325,7 @@ struct asd_sas_phy {
 	unsigned long phy_events_pending;
 
 	int error;
+	int suspended;
 
 	struct sas_phy *phy;
 
@@ -681,6 +688,9 @@ struct sas_domain_function_template {
 
 extern int sas_register_ha(struct sas_ha_struct *);
 extern int sas_unregister_ha(struct sas_ha_struct *);
+extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha);
+extern void sas_resume_ha(struct sas_ha_struct *sas_ha);
+extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
 
 int sas_set_phy_speed(struct sas_phy *phy,
 		      struct sas_phy_linkrates *rates);
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index 3e13c28..5bb5b1a 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -44,6 +44,8 @@ void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
 void sas_ata_schedule_reset(struct domain_device *dev);
 void sas_ata_wait_eh(struct domain_device *dev);
 void sas_probe_sata(struct asd_sas_port *port);
+void sas_suspend_sata(struct asd_sas_port *port);
+void sas_resume_sata(struct asd_sas_port *port);
 void sas_ata_end_eh(struct ata_port *ap);
 #else
 
@@ -78,6 +80,14 @@ static inline void sas_probe_sata(struct asd_sas_port *port)
 {
 }
 
+static inline void sas_suspend_sata(struct asd_sas_port *port)
+{
+}
+
+static inline void sas_resume_sata(struct asd_sas_port *port)
+{
+}
+
 static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
 {
 	return 0;


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

* [isci PATCH v2 17/18] isci: implement suspend/resume support
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (15 preceding siblings ...)
  2012-03-11  7:29 ` [isci PATCH v2 16/18] libsas: suspend / resume support Dan Williams
@ 2012-03-11  7:29 ` Dan Williams
  2012-03-11  7:29 ` [isci PATCH v2 18/18] isci: Changes in COMSAS timings enabling ISCI to detect buggy disc drives Dan Williams
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Artur Wojcik, Jacek Danecki

From: Artur Wojcik <artur.wojcik@intel.com>

Provide a "simple-dev-pm-ops" implementation that shuts down the domain
and the device on suspend, and resumes the device and the domain on
resume.  All of the mechanics of restoring domain connectivity are
handled by libsas once isci has notified libsas that all links should be
back up.  libsas is in charge of handling links that did not resume, or
resumed out of order.

Signed-off-by: Artur Wojcik <artur.wojcik@intel.com>
Signed-off-by: Jacek Danecki <jacek.danecki@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/host.c |    2 +-
 drivers/scsi/isci/host.h |    2 +-
 drivers/scsi/isci/init.c |   58 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 5832b13..2bafb55 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -1044,7 +1044,7 @@ static enum sci_status sci_controller_start(struct isci_host *ihost,
 	return SCI_SUCCESS;
 }
 
-void isci_host_scan_start(struct Scsi_Host *shost)
+void isci_host_start(struct Scsi_Host *shost)
 {
 	struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
 	unsigned long tmo = sci_controller_get_suggested_start_timeout(ihost);
diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h
index 7272a0a..bcd556f 100644
--- a/drivers/scsi/isci/host.h
+++ b/drivers/scsi/isci/host.h
@@ -470,7 +470,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost,
 
 enum sci_status sci_controller_continue_io(struct isci_request *ireq);
 int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
-void isci_host_scan_start(struct Scsi_Host *);
+void isci_host_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);
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index fdae42f..acf75c2 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -156,7 +156,7 @@ static struct scsi_host_template isci_sht = {
 	.target_alloc			= sas_target_alloc,
 	.slave_configure		= sas_slave_configure,
 	.scan_finished			= isci_host_scan_finished,
-	.scan_start			= isci_host_scan_start,
+	.scan_start			= isci_host_start,
 	.change_queue_depth		= sas_change_queue_depth,
 	.change_queue_type		= sas_change_queue_type,
 	.bios_param			= sas_bios_param,
@@ -722,11 +722,67 @@ static void __devexit isci_pci_remove(struct pci_dev *pdev)
 	}
 }
 
+#ifdef CONFIG_PM
+static int isci_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct isci_host *ihost;
+	int i;
+
+	for_each_isci_host(i, ihost, pdev) {
+		sas_suspend_ha(&ihost->sas_ha);
+		isci_host_deinit(ihost);
+	}
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+static int isci_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct isci_host *ihost;
+	int rc, i;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	rc = pcim_enable_device(pdev);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"enabling device failure after resume(%d)\n", rc);
+		return rc;
+	}
+
+	pci_set_master(pdev);
+
+	for_each_isci_host(i, ihost, pdev) {
+		sas_prep_resume_ha(&ihost->sas_ha);
+
+		isci_host_init(ihost);
+		isci_host_start(to_shost(ihost));
+		wait_for_start(ihost);
+
+		sas_resume_ha(&ihost->sas_ha);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(isci_pm_ops, isci_suspend, isci_resume);
+#endif
+
 static struct pci_driver isci_pci_driver = {
 	.name		= DRV_NAME,
 	.id_table	= isci_id_table,
 	.probe		= isci_pci_probe,
 	.remove		= __devexit_p(isci_pci_remove),
+#ifdef CONFIG_PM
+	.driver.pm      = &isci_pm_ops,
+#endif
 };
 
 static __init int isci_init(void)


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

* [isci PATCH v2 18/18] isci: Changes in COMSAS timings enabling ISCI to detect buggy disc drives.
  2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
                   ` (16 preceding siblings ...)
  2012-03-11  7:29 ` [isci PATCH v2 17/18] isci: implement suspend/resume support Dan Williams
@ 2012-03-11  7:29 ` Dan Williams
  17 siblings, 0 replies; 24+ messages in thread
From: Dan Williams @ 2012-03-11  7:29 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Andrzej Jakowski

From: Andrzej Jakowski <andrzej.jakowski@intel.com>

This patch extends timings in COMSAS signaling, so ISCI can detect disc
drives having issues to send COMSAS in correct time frame.

Signed-off-by: Andrzej Jakowski <andrzej.jakowski@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
 drivers/scsi/isci/phy.c       |   55 +++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/isci/registers.h |    8 ++++++
 2 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c
index 474330f..85b26ac 100644
--- a/drivers/scsi/isci/phy.c
+++ b/drivers/scsi/isci/phy.c
@@ -668,6 +668,19 @@ static const char *phy_event_name(u32 event_code)
 		phy_to_host(iphy)->id, iphy->phy_index, \
 		phy_state_name(state), phy_event_name(code), code)
 
+
+void scu_link_layer_set_txcomsas_timeout(struct isci_phy *iphy, u32 timeout)
+{
+	u32 val;
+
+	/* Extend timeout */
+	val = readl(&iphy->link_layer_registers->transmit_comsas_signal);
+	val &= ~SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK);
+	val |= SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, timeout);
+
+	writel(val, &iphy->link_layer_registers->transmit_comsas_signal);
+}
+
 enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 {
 	enum sci_phy_states state = iphy->sm.current_state_id;
@@ -683,6 +696,13 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 			sci_phy_start_sata_link_training(iphy);
 			iphy->is_in_link_training = true;
 			break;
+		case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+		       /* Extend timeout value */
+		       scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
+
+		       /* Start the oob/sn state machine over again */
+		       sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+		       break;
 		default:
 			phy_event_dbg(iphy, state, event_code);
 			return SCI_FAILURE;
@@ -717,9 +737,19 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 			sci_phy_start_sata_link_training(iphy);
 			break;
 		case SCU_EVENT_LINK_FAILURE:
+			/* Change the timeout value to default */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
+		case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+		       /* Extend the timeout value */
+		       scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
+
+		       /* Start the oob/sn state machine over again */
+		       sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+		       break;
 		default:
 			phy_event_warn(iphy, state, event_code);
 			return SCI_FAILURE;
@@ -740,7 +770,14 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 			sci_phy_start_sata_link_training(iphy);
 			break;
 		case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
+			/* Extend the timeout value */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
+
+			/* Start the oob/sn state machine over again */
+			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
+			break;
 		case SCU_EVENT_LINK_FAILURE:
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
 		case SCU_EVENT_HARD_RESET_RECEIVED:
 			/* Start the oob/sn state machine over again */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
@@ -753,6 +790,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 	case SCI_PHY_SUB_AWAIT_SAS_POWER:
 		switch (scu_get_event_code(event_code)) {
 		case SCU_EVENT_LINK_FAILURE:
+			/* Change the timeout value to default */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
@@ -764,6 +804,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 	case SCI_PHY_SUB_AWAIT_SATA_POWER:
 		switch (scu_get_event_code(event_code)) {
 		case SCU_EVENT_LINK_FAILURE:
+			/* Change the timeout value to default */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
@@ -788,6 +831,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 	case SCI_PHY_SUB_AWAIT_SATA_PHY_EN:
 		switch (scu_get_event_code(event_code)) {
 		case SCU_EVENT_LINK_FAILURE:
+			/* Change the timeout value to default */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
@@ -836,6 +882,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 						       SCI_PHY_SUB_AWAIT_SIG_FIS_UF);
 			break;
 		case SCU_EVENT_LINK_FAILURE:
+			/* Change the timeout value to default */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
@@ -859,6 +908,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 			break;
 
 		case SCU_EVENT_LINK_FAILURE:
+			/* Change the timeout value to default */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
@@ -871,6 +923,9 @@ enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code)
 	case SCI_PHY_READY:
 		switch (scu_get_event_code(event_code)) {
 		case SCU_EVENT_LINK_FAILURE:
+			/* Set default timeout */
+			scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
+
 			/* Link failure change state back to the starting state */
 			sci_change_state(&iphy->sm, SCI_PHY_STARTING);
 			break;
diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h
index f232f7e..6fe0141 100644
--- a/drivers/scsi/isci/registers.h
+++ b/drivers/scsi/isci/registers.h
@@ -1239,6 +1239,14 @@ struct scu_transport_layer_registers {
 #define SCU_SAS_LLCTL_GEN_BIT(name) \
 	SCU_GEN_BIT(SCU_SAS_LINK_LAYER_CONTROL_ ## name)
 
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT                     (0xF0)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED                    (0x1FF)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_SHIFT                       (0)
+#define SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK                        (0x3FF)
+
+#define SCU_SAS_LLTXCOMSAS_GEN_VAL(name, value) \
+	SCU_GEN_VALUE(SCU_SAS_LINK_LAYER_TXCOMSAS_ ## name, value)
+
 
 /* #define SCU_FRXHECR_DCNT_OFFSET      0x00B0 */
 #define SCU_PSZGCR_OFFSET           0x00E4


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

* Re: [isci PATCH v2 16/18] libsas: suspend / resume support
  2012-03-11  7:29 ` [isci PATCH v2 16/18] libsas: suspend / resume support Dan Williams
@ 2012-03-11  8:06   ` jack_wang
  0 siblings, 0 replies; 24+ messages in thread
From: jack_wang @ 2012-03-11  8:06 UTC (permalink / raw)
  To: Dan Williams, linux-scsi; +Cc: linux-ide, Jacek Danecki

Really nice, pm8001 has a broken suspend/resume implementation, will try to use
this infrastructure to test.

Thanks.

BTW:

> enum discover_event {
>@@ -87,8 +88,10 @@ enum discover_event {
> 	DISCE_REVALIDATE_DOMAIN = 1,
> 	DISCE_PORT_GONE         = 2,
> 	DISCE_PROBE		= 3,
>-	DISCE_DESTRUCT		= 4,
>-	DISC_NUM_EVENTS		= 5,
>+	DISCE_SUSPEND		= 4,
>+	DISCE_RESUME		= 5,
>+	DISCE_DESTRUCT		= 6,
>+	DISC_NUM_EVENTS		= 7,
> };
DISCE_PORT_GONE seems never in use, so we only have 6 DISC_NUM_EVENTS.


--------------
jack_wang
>libsas power management routines to suspend and recover the sas domain
>based on a model where the lldd is allowed and expected to be
>"forgetful".
>
>sas_suspend_ha - disable event processing allowing the lldd to take down
>                 links without concern for causing hotplug events.
>                 Regardless of whether the lldd actually posts link down
>                 messages libsas notifies the lldd that all
>                 domain_devices are gone.
>
>sas_prep_resume_ha - on the way back up before the lldd starts link
>                     training clean out any spurious events that were
>                     generated on the way down, and re-enable event
>                     processing
>
>sas_resume_ha - after the lldd has started and decided that all phys
>		have posted link-up events this routine is called to let
>		libsas start it's own timeout of any phys that did not
>		resume.  After the timeout an lldd can cancel the
>                phy teardown by posting a link-up event.
>
>Storage for ex_change_count (u16) and phy_change_count (u8) are changed
>to int so they can be set to -1 to indicate 'invalidated'.
>
>Reviewed-by: Jacek Danecki <jacek.danecki@intel.com>
>Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>---
> drivers/scsi/libsas/sas_ata.c       |   86 +++++++++++++++++++++++++++++++++
> drivers/scsi/libsas/sas_discover.c  |   68 +++++++++++++++++++++++---
> drivers/scsi/libsas/sas_dump.c      |    1 
> drivers/scsi/libsas/sas_event.c     |    4 +-
> drivers/scsi/libsas/sas_init.c      |   90 +++++++++++++++++++++++++++++++++++
> drivers/scsi/libsas/sas_internal.h  |    2 +
> drivers/scsi/libsas/sas_phy.c       |   21 ++++++++
> drivers/scsi/libsas/sas_port.c      |   52 ++++++++++++++++++++
> drivers/scsi/libsas/sas_scsi_host.c |    2 -
> include/scsi/libsas.h               |   20 ++++++--
> include/scsi/sas_ata.h              |   10 ++++
> 11 files changed, 336 insertions(+), 20 deletions(-)
>
>diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
>index d30a093..b161bdd 100644
>--- a/drivers/scsi/libsas/sas_ata.c
>+++ b/drivers/scsi/libsas/sas_ata.c
>@@ -677,6 +677,92 @@ void sas_probe_sata(struct asd_sas_port *port)
> 		if (ata_dev_disabled(sas_to_ata_dev(dev)))
> 			sas_fail_probe(dev, __func__, -ENODEV);
> 	}
>+
>+}
>+
>+static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
>+{
>+	struct domain_device *dev, *n;
>+	bool retry = false;
>+
>+	list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
>+		int rc;
>+
>+		if (!dev_is_sata(dev))
>+			continue;
>+
>+		sas_ata_wait_eh(dev);
>+		rc = dev->sata_dev.pm_result;
>+		if (rc == -EAGAIN)
>+			retry = true;
>+		else if (rc) {
>+			/* since we don't have a
>+			 * ->port_{suspend|resume} routine in our
>+			 *  ata_port ops, and no entanglements with
>+			 *  acpi, suspend should just be mechanical trip
>+			 *  through eh, catch cases where these
>+			 *  assumptions are invalidated
>+			 */
>+			WARN_ONCE(1, "failed %s %s error: %d\n", func,
>+				 dev_name(&dev->rphy->dev), rc);
>+		}
>+
>+		/* if libata failed to power manage the device, tear it down */
>+		if (ata_dev_disabled(sas_to_ata_dev(dev)))
>+			sas_fail_probe(dev, func, -ENODEV);
>+	}
>+
>+	return retry;
>+}
>+
>+void sas_suspend_sata(struct asd_sas_port *port)
>+{
>+	struct domain_device *dev;
>+
>+ retry:
>+	mutex_lock(&port->ha->disco_mutex);
>+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
>+		struct sata_device *sata;
>+
>+		if (!dev_is_sata(dev))
>+			continue;
>+
>+		sata = &dev->sata_dev;
>+		if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
>+			continue;
>+
>+		sata->pm_result = -EIO;
>+		ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
>+	}
>+	mutex_unlock(&port->ha->disco_mutex);
>+
>+	if (sas_ata_flush_pm_eh(port, __func__))
>+		goto retry;
>+}
>+
>+void sas_resume_sata(struct asd_sas_port *port)
>+{
>+	struct domain_device *dev;
>+
>+ retry:
>+	mutex_lock(&port->ha->disco_mutex);
>+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
>+		struct sata_device *sata;
>+
>+		if (!dev_is_sata(dev))
>+			continue;
>+
>+		sata = &dev->sata_dev;
>+		if (sata->ap->pm_mesg.event == PM_EVENT_ON)
>+			continue;
>+
>+		sata->pm_result = -EIO;
>+		ata_sas_port_async_resume(sata->ap, &sata->pm_result);
>+	}
>+	mutex_unlock(&port->ha->disco_mutex);
>+
>+	if (sas_ata_flush_pm_eh(port, __func__))
>+		goto retry;
> }
> 
> /**
>diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
>index a98fe6e..8b1b4ef 100644
>--- a/drivers/scsi/libsas/sas_discover.c
>+++ b/drivers/scsi/libsas/sas_discover.c
>@@ -171,16 +171,18 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
> 	struct Scsi_Host *shost = sas_ha->core.shost;
> 	struct sas_internal *i = to_sas_internal(shost->transportt);
> 
>-	if (i->dft->lldd_dev_found) {
>-		res = i->dft->lldd_dev_found(dev);
>-		if (res) {
>-			printk("sas: driver on pcidev %s cannot handle "
>-			       "device %llx, error:%d\n",
>-			       dev_name(sas_ha->dev),
>-			       SAS_ADDR(dev->sas_addr), res);
>-		}
>-		kref_get(&dev->kref);
>+	if (!i->dft->lldd_dev_found)
>+		return 0;
>+
>+	res = i->dft->lldd_dev_found(dev);
>+	if (res) {
>+		printk("sas: driver on pcidev %s cannot handle "
>+		       "device %llx, error:%d\n",
>+		       dev_name(sas_ha->dev),
>+		       SAS_ADDR(dev->sas_addr), res);
> 	}
>+	set_bit(SAS_DEV_FOUND, &dev->state);
>+	kref_get(&dev->kref);
> 	return res;
> }
> 
>@@ -191,7 +193,10 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
> 	struct Scsi_Host *shost = sas_ha->core.shost;
> 	struct sas_internal *i = to_sas_internal(shost->transportt);
> 
>-	if (i->dft->lldd_dev_gone) {
>+	if (!i->dft->lldd_dev_gone)
>+		return;
>+
>+	if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
> 		i->dft->lldd_dev_gone(dev);
> 		sas_put_device(dev);
> 	}
>@@ -225,6 +230,47 @@ static void sas_probe_devices(struct work_struct *work)
> 	}
> }
> 
>+static void sas_suspend_devices(struct work_struct *work)
>+{
>+	struct asd_sas_phy *phy;
>+	struct domain_device *dev;
>+	struct sas_discovery_event *ev = to_sas_discovery_event(work);
>+	struct asd_sas_port *port = ev->port;
>+	struct Scsi_Host *shost = port->ha->core.shost;
>+	struct sas_internal *si = to_sas_internal(shost->transportt);
>+
>+	clear_bit(DISCE_SUSPEND, &port->disc.pending);
>+
>+	sas_suspend_sata(port);
>+
>+	/* lldd is free to forget the domain_device across the
>+	 * suspension, we force the issue here to keep the reference
>+	 * counts aligned
>+	 */
>+	list_for_each_entry(dev, &port->dev_list, dev_list_node)
>+		sas_notify_lldd_dev_gone(dev);
>+
>+	/* we are suspending, so we know events are disabled and
>+	 * phy_list is not being mutated
>+	 */
>+	list_for_each_entry(phy, &port->phy_list, port_phy_el) {
>+		if (si->dft->lldd_port_formed)
>+			si->dft->lldd_port_deformed(phy);
>+		phy->suspended = 1;
>+		port->suspended = 1;
>+	}
>+}
>+
>+static void sas_resume_devices(struct work_struct *work)
>+{
>+	struct sas_discovery_event *ev = to_sas_discovery_event(work);
>+	struct asd_sas_port *port = ev->port;
>+
>+	clear_bit(DISCE_RESUME, &port->disc.pending);
>+
>+	sas_resume_sata(port);
>+}
>+
> /**
>  * sas_discover_end_dev -- discover an end device (SSP, etc)
>  * @end: pointer to domain device of interest
>@@ -521,6 +567,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
> 		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
> 		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
> 		[DISCE_PROBE] = sas_probe_devices,
>+		[DISCE_SUSPEND] = sas_suspend_devices,
>+		[DISCE_RESUME] = sas_resume_devices,
> 		[DISCE_DESTRUCT] = sas_destruct_devices,
> 	};
> 
>diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
>index fc46093..cd6f99c 100644
>--- a/drivers/scsi/libsas/sas_dump.c
>+++ b/drivers/scsi/libsas/sas_dump.c
>@@ -41,6 +41,7 @@ static const char *sas_phye_str[] = {
> 	[1] = "PHYE_OOB_DONE",
> 	[2] = "PHYE_OOB_ERROR",
> 	[3] = "PHYE_SPINUP_HOLD",
>+	[4] = "PHYE_RESUME_TIMEOUT",
> };
> 
> void sas_dprint_porte(int phyid, enum port_event pe)
>diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
>index 789c4d8..aadbd53 100644
>--- a/drivers/scsi/libsas/sas_event.c
>+++ b/drivers/scsi/libsas/sas_event.c
>@@ -134,7 +134,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
> 			&phy->port_events[event].work, ha);
> }
> 
>-static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
>+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
> {
> 	struct sas_ha_struct *ha = phy->ha;
> 
>@@ -159,7 +159,7 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
> 
> 	sas_ha->notify_ha_event = notify_ha_event;
> 	sas_ha->notify_port_event = notify_port_event;
>-	sas_ha->notify_phy_event = notify_phy_event;
>+	sas_ha->notify_phy_event = sas_notify_phy_event;
> 
> 	return 0;
> }
>diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
>index 1bbab3d..29c0910 100644
>--- a/drivers/scsi/libsas/sas_init.c
>+++ b/drivers/scsi/libsas/sas_init.c
>@@ -159,7 +159,7 @@ Undo_phys:
> 	return error;
> }
> 
>-int sas_unregister_ha(struct sas_ha_struct *sas_ha)
>+static void sas_disable_events(struct sas_ha_struct *sas_ha)
> {
> 	/* Set the state to unregistered to avoid further unchained
> 	 * events to be queued, and flush any in-progress drainers
>@@ -170,7 +170,11 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
> 	spin_unlock_irq(&sas_ha->lock);
> 	__sas_drain_work(sas_ha);
> 	mutex_unlock(&sas_ha->drain_mutex);
>+}
> 
>+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
>+{
>+	sas_disable_events(sas_ha);
> 	sas_unregister_ports(sas_ha);
> 
> 	/* flush unregistration work */
>@@ -362,6 +366,90 @@ int sas_set_phy_speed(struct sas_phy *phy,
> 	return ret;
> }
> 
>+void sas_prep_resume_ha(struct sas_ha_struct *ha)
>+{
>+	int i;
>+
>+	set_bit(SAS_HA_REGISTERED, &ha->state);
>+
>+	/* clear out any stale link events/data from the suspension path */
>+	for (i = 0; i < ha->num_phys; i++) {
>+		struct asd_sas_phy *phy = ha->sas_phy[i];
>+
>+		memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
>+		phy->port_events_pending = 0;
>+		phy->phy_events_pending = 0;
>+		phy->frame_rcvd_size = 0;
>+	}
>+}
>+EXPORT_SYMBOL(sas_prep_resume_ha);
>+
>+static int phys_suspended(struct sas_ha_struct *ha)
>+{
>+	int i, rc = 0;
>+
>+	for (i = 0; i < ha->num_phys; i++) {
>+		struct asd_sas_phy *phy = ha->sas_phy[i];
>+
>+		if (phy->suspended)
>+			rc++;
>+	}
>+
>+	return rc;
>+}
>+
>+void sas_resume_ha(struct sas_ha_struct *ha)
>+{
>+	const unsigned long tmo = msecs_to_jiffies(25000);
>+	int i;
>+
>+	/* deform ports on phys that did not resume
>+	 * at this point we may be racing the phy coming back (as posted
>+	 * by the lldd).  So we post the event and once we are in the
>+	 * libsas context check that the phy remains suspended before
>+	 * tearing it down.
>+	 */
>+	i = phys_suspended(ha);
>+	if (i)
>+		dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
>+			 i, i > 1 ? "s" : "");
>+	wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
>+	for (i = 0; i < ha->num_phys; i++) {
>+		struct asd_sas_phy *phy = ha->sas_phy[i];
>+
>+		if (phy->suspended) {
>+			dev_warn(&phy->phy->dev, "resume timeout\n");
>+			sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT);
>+		}
>+	}
>+
>+	/* all phys are back up or timed out, turn on i/o so we can
>+	 * flush out disks that did not return
>+	 */
>+	scsi_unblock_requests(ha->core.shost);
>+	sas_drain_work(ha);
>+}
>+EXPORT_SYMBOL(sas_resume_ha);
>+
>+void sas_suspend_ha(struct sas_ha_struct *ha)
>+{
>+	int i;
>+
>+	sas_disable_events(ha);
>+	scsi_block_requests(ha->core.shost);
>+	for (i = 0; i < ha->num_phys; i++) {
>+		struct asd_sas_port *port = ha->sas_port[i];
>+
>+		sas_discover_event(port, DISCE_SUSPEND);
>+	}
>+
>+	/* flush suspend events while unregistered */
>+	mutex_lock(&ha->drain_mutex);
>+	__sas_drain_work(ha);
>+	mutex_unlock(&ha->drain_mutex);
>+}
>+EXPORT_SYMBOL(sas_suspend_ha);
>+
> static void sas_phy_release(struct sas_phy *phy)
> {
> 	kfree(phy->hostdata);
>diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
>index 507e4cf..a91028e 100644
>--- a/drivers/scsi/libsas/sas_internal.h
>+++ b/drivers/scsi/libsas/sas_internal.h
>@@ -88,7 +88,9 @@ void sas_notify_lldd_dev_gone(struct domain_device *);
> int sas_smp_phy_control(struct domain_device *dev, int phy_id,
> 			enum phy_func phy_func, struct sas_phy_linkrates *);
> int sas_smp_get_phy_events(struct sas_phy *phy);
>+int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait);
> 
>+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
> void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
> struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
> struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
>diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
>index 521422e..cdee446 100644
>--- a/drivers/scsi/libsas/sas_phy.c
>+++ b/drivers/scsi/libsas/sas_phy.c
>@@ -94,6 +94,25 @@ static void sas_phye_spinup_hold(struct work_struct *work)
> 	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
> }
> 
>+static void sas_phye_resume_timeout(struct work_struct *work)
>+{
>+	struct asd_sas_event *ev = to_asd_sas_event(work);
>+	struct asd_sas_phy *phy = ev->phy;
>+
>+	clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
>+
>+	/* phew, lldd got the phy back in the nick of time */
>+	if (!phy->suspended) {
>+		dev_info(&phy->phy->dev, "resume timeout cancelled\n");
>+		return;
>+	}
>+
>+	phy->error = 0;
>+	phy->suspended = 0;
>+	sas_deform_port(phy, 1);
>+}
>+
>+
> /* ---------- Phy class registration ---------- */
> 
> int sas_register_phys(struct sas_ha_struct *sas_ha)
>@@ -105,6 +124,8 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
> 		[PHYE_OOB_DONE] = sas_phye_oob_done,
> 		[PHYE_OOB_ERROR] = sas_phye_oob_error,
> 		[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
>+		[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
>+
> 	};
> 
> 	static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
>diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
>index 1cf7d75..1ac0c8b 100644
>--- a/drivers/scsi/libsas/sas_port.c
>+++ b/drivers/scsi/libsas/sas_port.c
>@@ -39,6 +39,49 @@ static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy
> 	return true;
> }
> 
>+static void sas_resume_port(struct asd_sas_phy *phy)
>+{
>+	struct domain_device *dev;
>+	struct asd_sas_port *port = phy->port;
>+	struct sas_ha_struct *sas_ha = phy->ha;
>+	struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt);
>+
>+	if (si->dft->lldd_port_formed)
>+		si->dft->lldd_port_formed(phy);
>+
>+	if (port->suspended)
>+		port->suspended = 0;
>+	else {
>+		/* we only need to handle "link returned" actions once */
>+		return;
>+	}
>+
>+	/* if the port came back:
>+	 * 1/ presume every device came back
>+	 * 2/ force the next revalidation to check all expander phys
>+	 */
>+	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
>+		int i, rc;
>+
>+		rc = sas_notify_lldd_dev_found(dev);
>+		if (rc) {
>+			sas_unregister_dev(port, dev);
>+			continue;
>+		}
>+
>+		if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
>+			dev->ex_dev.ex_change_count = -1;
>+			for (i = 0; i < dev->ex_dev.num_phys; i++) {
>+				struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
>+
>+				phy->phy_change_count = -1;
>+			}
>+		}
>+	}
>+
>+	sas_discover_event(port, DISCE_RESUME);
>+}
>+
> /**
>  * sas_form_port -- add this phy to a port
>  * @phy: the phy of interest
>@@ -58,7 +101,14 @@ static void sas_form_port(struct asd_sas_phy *phy)
> 	if (port) {
> 		if (!phy_is_wideport_member(port, phy))
> 			sas_deform_port(phy, 0);
>-		else {
>+		else if (phy->suspended) {
>+			phy->suspended = 0;
>+			sas_resume_port(phy);
>+
>+			/* phy came back, try to cancel the timeout */
>+			wake_up(&sas_ha->eh_wait_q);
>+			return;
>+		} else {
> 			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
> 				    __func__, phy->id, phy->port->id,
> 				    phy->port->num_phys);
>diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
>index 50a18a6..07fba82 100644
>--- a/drivers/scsi/libsas/sas_scsi_host.c
>+++ b/drivers/scsi/libsas/sas_scsi_host.c
>@@ -490,7 +490,7 @@ static void sas_wait_eh(struct domain_device *dev)
> }
> EXPORT_SYMBOL(sas_wait_eh);
> 
>-static int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
>+int sas_queue_reset(struct domain_device *dev, int reset_type, int lun, int wait)
> {
> 	struct sas_ha_struct *ha = dev->port->ha;
> 	int scheduled = 0, tries = 100;
>diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
>index ad5229a..74e17fa 100644
>--- a/include/scsi/libsas.h
>+++ b/include/scsi/libsas.h
>@@ -79,7 +79,8 @@ enum phy_event {
> 	PHYE_OOB_DONE         = 1,
> 	PHYE_OOB_ERROR        = 2,
> 	PHYE_SPINUP_HOLD      = 3, /* hot plug SATA, no COMWAKE sent */
>-	PHY_NUM_EVENTS        = 4,
>+	PHYE_RESUME_TIMEOUT   = 4,
>+	PHY_NUM_EVENTS        = 5,
> };
> 
> enum discover_event {
>@@ -87,8 +88,10 @@ enum discover_event {
> 	DISCE_REVALIDATE_DOMAIN = 1,
> 	DISCE_PORT_GONE         = 2,
> 	DISCE_PROBE		= 3,
>-	DISCE_DESTRUCT		= 4,
>-	DISC_NUM_EVENTS		= 5,
>+	DISCE_SUSPEND		= 4,
>+	DISCE_RESUME		= 5,
>+	DISCE_DESTRUCT		= 6,
>+	DISC_NUM_EVENTS		= 7,
> };
> 
> /* ---------- Expander Devices ---------- */
>@@ -128,7 +131,7 @@ struct ex_phy {
> 	u8   attached_sas_addr[SAS_ADDR_SIZE];
> 	u8   attached_phy_id;
> 
>-	u8   phy_change_count;
>+	int phy_change_count;
> 	enum routing_attribute routing_attr;
> 	u8   virtual:1;
> 
>@@ -141,7 +144,7 @@ struct ex_phy {
> struct expander_device {
> 	struct list_head children;
> 
>-	u16    ex_change_count;
>+	int    ex_change_count;
> 	u16    max_route_indexes;
> 	u8     num_phys;
> 
>@@ -167,6 +170,7 @@ struct sata_device {
>         enum   ata_command_set command_set;
>         struct smp_resp        rps_resp; /* report_phy_sata_resp */
>         u8     port_no;        /* port number, if this is a PM (Port) */
>+	int    pm_result;
> 
> 	struct ata_port *ap;
> 	struct ata_host ata_host;
>@@ -180,6 +184,7 @@ struct ssp_device {
> 
> enum {
> 	SAS_DEV_GONE,
>+	SAS_DEV_FOUND, /* device notified to lldd */
> 	SAS_DEV_DESTROY,
> 	SAS_DEV_EH_PENDING,
> 	SAS_DEV_LU_RESET,
>@@ -271,6 +276,7 @@ struct asd_sas_port {
> 	enum   sas_linkrate linkrate;
> 
> 	struct sas_work work;
>+	int suspended;
> 
> /* public: */
> 	int id;
>@@ -319,6 +325,7 @@ struct asd_sas_phy {
> 	unsigned long phy_events_pending;
> 
> 	int error;
>+	int suspended;
> 
> 	struct sas_phy *phy;
> 
>@@ -681,6 +688,9 @@ struct sas_domain_function_template {
> 
> extern int sas_register_ha(struct sas_ha_struct *);
> extern int sas_unregister_ha(struct sas_ha_struct *);
>+extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha);
>+extern void sas_resume_ha(struct sas_ha_struct *sas_ha);
>+extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
> 
> int sas_set_phy_speed(struct sas_phy *phy,
> 		      struct sas_phy_linkrates *rates);
>diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
>index 3e13c28..5bb5b1a 100644
>--- a/include/scsi/sas_ata.h
>+++ b/include/scsi/sas_ata.h
>@@ -44,6 +44,8 @@ void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
> void sas_ata_schedule_reset(struct domain_device *dev);
> void sas_ata_wait_eh(struct domain_device *dev);
> void sas_probe_sata(struct asd_sas_port *port);
>+void sas_suspend_sata(struct asd_sas_port *port);
>+void sas_resume_sata(struct asd_sas_port *port);
> void sas_ata_end_eh(struct ata_port *ap);
> #else
> 
>@@ -78,6 +80,14 @@ static inline void sas_probe_sata(struct asd_sas_port *port)
> {
> }
> 
>+static inline void sas_suspend_sata(struct asd_sas_port *port)
>+{
>+}
>+
>+static inline void sas_resume_sata(struct asd_sas_port *port)
>+{
>+}
>+
> static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
> {
> 	return 0;
>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>__________ Information from ESET NOD32 Antivirus, version of virus signature database 5659 (20101129) __________
>
>The message was checked by ESET NOD32 Antivirus.
>
>http://www.eset.com
>
>
>

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

* Re: [isci PATCH v2 12/18] libata: make ata_print_id atomic
  2012-03-11  7:28 ` [isci PATCH v2 12/18] libata: make ata_print_id atomic Dan Williams
@ 2012-04-11  2:21   ` Dan Williams
  2012-04-11 11:42     ` Jacek Danecki
  2012-04-12 19:58   ` Jeff Garzik
  1 sibling, 1 reply; 24+ messages in thread
From: Dan Williams @ 2012-04-11  2:21 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-ide, Jacek Danecki, Jeff Garzik

Ping? I assume this fairly uncontroversial and can be 3.4-rc material.

On Sat, Mar 10, 2012 at 11:28 PM, Dan Williams <dan.j.williams@intel.com> wrote:
> This variable is incremented from multiple contexts (module_init via
> libata-lldds and the libsas discovery thread).  Make it atomic to head
> off any chance of libsas and libata creating duplicate ids.
>
> Acked-by: Jacek Danecki <jacek.danecki@intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
>  drivers/ata/libata-core.c |    4 ++--
>  drivers/ata/libata-scsi.c |    4 ++--
>  drivers/ata/libata.h      |    2 +-
>  3 files changed, 5 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index ea8444e..bd79c8b 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -97,7 +97,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
>  static void ata_dev_xfermask(struct ata_device *dev);
>  static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
>
> -unsigned int ata_print_id = 1;
> +atomic_t ata_print_id = ATOMIC_INIT(1);
>
>  struct ata_force_param {
>        const char      *name;
> @@ -6031,7 +6031,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
>
>        /* give ports names and add SCSI hosts */
>        for (i = 0; i < host->n_ports; i++)
> -               host->ports[i]->print_id = ata_print_id++;
> +               host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
>
>
>        /* Create associated sysfs transport objects  */
> diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
> index 1ee00c8..93dabdc 100644
> --- a/drivers/ata/libata-scsi.c
> +++ b/drivers/ata/libata-scsi.c
> @@ -3843,7 +3843,7 @@ int ata_sas_async_port_init(struct ata_port *ap)
>        int rc = ap->ops->port_start(ap);
>
>        if (!rc) {
> -               ap->print_id = ata_print_id++;
> +               ap->print_id = atomic_inc_return(&ata_print_id);
>                __ata_port_probe(ap);
>        }
>
> @@ -3867,7 +3867,7 @@ int ata_sas_port_init(struct ata_port *ap)
>        int rc = ap->ops->port_start(ap);
>
>        if (!rc) {
> -               ap->print_id = ata_print_id++;
> +               ap->print_id = atomic_inc_return(&ata_print_id);
>                rc = ata_port_probe(ap);
>        }
>
> diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
> index 2e26fca..9d0fd0b 100644
> --- a/drivers/ata/libata.h
> +++ b/drivers/ata/libata.h
> @@ -53,7 +53,7 @@ enum {
>        ATA_DNXFER_QUIET        = (1 << 31),
>  };
>
> -extern unsigned int ata_print_id;
> +extern atomic_t ata_print_id;
>  extern int atapi_passthru16;
>  extern int libata_fua;
>  extern int libata_noacpi;
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [isci PATCH v2 12/18] libata: make ata_print_id atomic
  2012-04-11  2:21   ` Dan Williams
@ 2012-04-11 11:42     ` Jacek Danecki
  2012-04-11 13:42       ` jack_wang
  0 siblings, 1 reply; 24+ messages in thread
From: Jacek Danecki @ 2012-04-11 11:42 UTC (permalink / raw)
  To: Dan Williams; +Cc: linux-scsi, linux-ide, Jeff Garzik

On 04/11/12 04:21, Dan Williams wrote:
> Ping? I assume this fairly uncontroversial and can be 3.4-rc material.
>

Acked-by: Jacek Danecki <jacek.danecki@intel.com>
-- 
Jacek

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

* Re: Re: [isci PATCH v2 12/18] libata: make ata_print_id atomic
  2012-04-11 11:42     ` Jacek Danecki
@ 2012-04-11 13:42       ` jack_wang
  0 siblings, 0 replies; 24+ messages in thread
From: jack_wang @ 2012-04-11 13:42 UTC (permalink / raw)
  To: Jacek Danecki, Dan Williams; +Cc: linux-scsi, linux-ide, Jeff Garzik

Acked-by: Jack Wang <jack_wang@usish.com>



--------------
jack_wang
>On 04/11/12 04:21, Dan Williams wrote:
>> Ping? I assume this fairly uncontroversial and can be 3.4-rc material.
>>
>
>Acked-by: Jacek Danecki <jacek.danecki@intel.com>
>-- 
>Jacek
>--
>To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>__________ Information from ESET NOD32 Antivirus, version of virus signature database 5659 (20101129) __________
>
>The message was checked by ESET NOD32 Antivirus.
>
>http://www.eset.com
>
>
>

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

* Re: [isci PATCH v2 12/18] libata: make ata_print_id atomic
  2012-03-11  7:28 ` [isci PATCH v2 12/18] libata: make ata_print_id atomic Dan Williams
  2012-04-11  2:21   ` Dan Williams
@ 2012-04-12 19:58   ` Jeff Garzik
  1 sibling, 0 replies; 24+ messages in thread
From: Jeff Garzik @ 2012-04-12 19:58 UTC (permalink / raw)
  To: Dan Williams; +Cc: linux-scsi, linux-ide, Jacek Danecki

On 03/11/2012 03:28 AM, Dan Williams wrote:
> This variable is incremented from multiple contexts (module_init via
> libata-lldds and the libsas discovery thread).  Make it atomic to head
> off any chance of libsas and libata creating duplicate ids.
>
> Acked-by: Jacek Danecki<jacek.danecki@intel.com>
> Signed-off-by: Dan Williams<dan.j.williams@intel.com>
> ---
>   drivers/ata/libata-core.c |    4 ++--
>   drivers/ata/libata-scsi.c |    4 ++--
>   drivers/ata/libata.h      |    2 +-
>   3 files changed, 5 insertions(+), 5 deletions(-)

applied




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

end of thread, other threads:[~2012-04-12 19:58 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-11  7:27 [isci PATCH v2 00/18] isci: suspend/resume support + general updates Dan Williams
2012-03-11  7:27 ` [isci PATCH v2 01/18] isci: improve 'invalid state' warnings Dan Williams
2012-03-11  7:27 ` [isci PATCH v2 02/18] isci: kill ->is_direct_attached Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 03/18] isci: kill sci_phy_protocol and sci_request_protocol Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 04/18] isci: Don't filter BROADCAST CHANGE primitives Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 05/18] isci: kill ->status, and ->state_lock in isci_host Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 06/18] isci: kill isci_port.domain_dev_list Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 07/18] isci: refactor initialization for S3/S4 Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 08/18] isci: fix controller stop Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 09/18] isci: fix 'link-up' events occur after 'start-complete' Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 10/18] isci: fix interrupt disable Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 11/18] isci: kill isci_host.shost Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 12/18] libata: make ata_print_id atomic Dan Williams
2012-04-11  2:21   ` Dan Williams
2012-04-11 11:42     ` Jacek Danecki
2012-04-11 13:42       ` jack_wang
2012-04-12 19:58   ` Jeff Garzik
2012-03-11  7:28 ` [isci PATCH v2 13/18] libsas: continue revalidation Dan Williams
2012-03-11  7:28 ` [isci PATCH v2 14/18] libata: export ata_port suspend/resume infrastructure for sas Dan Williams
2012-03-11  7:29 ` [isci PATCH v2 15/18] libsas: drop sata port multiplier infrastructure Dan Williams
2012-03-11  7:29 ` [isci PATCH v2 16/18] libsas: suspend / resume support Dan Williams
2012-03-11  8:06   ` jack_wang
2012-03-11  7:29 ` [isci PATCH v2 17/18] isci: implement suspend/resume support Dan Williams
2012-03-11  7:29 ` [isci PATCH v2 18/18] isci: Changes in COMSAS timings enabling ISCI to detect buggy disc drives 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.