Re: [isci PATCH v2 16/18] libsas: suspend / resume support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
>Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
>---
> 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@xxxxxxxxxxxxxxx
>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
>
>
>?韬{.n?????%??檩??w?{.n???{炳'^??骅w*jg????????G??⒏⒎?:+v????????????"??????


[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux