aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libsas/sas_ata.c86
-rw-r--r--drivers/scsi/libsas/sas_discover.c69
-rw-r--r--drivers/scsi/libsas/sas_dump.c1
-rw-r--r--drivers/scsi/libsas/sas_event.c4
-rw-r--r--drivers/scsi/libsas/sas_init.c90
-rw-r--r--drivers/scsi/libsas/sas_internal.h1
-rw-r--r--drivers/scsi/libsas/sas_phy.c21
-rw-r--r--drivers/scsi/libsas/sas_port.c52
-rw-r--r--include/scsi/libsas.h20
-rw-r--r--include/scsi/sas_ata.h10
10 files changed, 335 insertions, 19 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index a59fcdc8fd63..905ae45133fc 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -700,6 +700,92 @@ void sas_probe_sata(struct asd_sas_port *port)
700 if (ata_dev_disabled(sas_to_ata_dev(dev))) 700 if (ata_dev_disabled(sas_to_ata_dev(dev)))
701 sas_fail_probe(dev, __func__, -ENODEV); 701 sas_fail_probe(dev, __func__, -ENODEV);
702 } 702 }
703
704}
705
706static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
707{
708 struct domain_device *dev, *n;
709 bool retry = false;
710
711 list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
712 int rc;
713
714 if (!dev_is_sata(dev))
715 continue;
716
717 sas_ata_wait_eh(dev);
718 rc = dev->sata_dev.pm_result;
719 if (rc == -EAGAIN)
720 retry = true;
721 else if (rc) {
722 /* since we don't have a
723 * ->port_{suspend|resume} routine in our
724 * ata_port ops, and no entanglements with
725 * acpi, suspend should just be mechanical trip
726 * through eh, catch cases where these
727 * assumptions are invalidated
728 */
729 WARN_ONCE(1, "failed %s %s error: %d\n", func,
730 dev_name(&dev->rphy->dev), rc);
731 }
732
733 /* if libata failed to power manage the device, tear it down */
734 if (ata_dev_disabled(sas_to_ata_dev(dev)))
735 sas_fail_probe(dev, func, -ENODEV);
736 }
737
738 return retry;
739}
740
741void sas_suspend_sata(struct asd_sas_port *port)
742{
743 struct domain_device *dev;
744
745 retry:
746 mutex_lock(&port->ha->disco_mutex);
747 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
748 struct sata_device *sata;
749
750 if (!dev_is_sata(dev))
751 continue;
752
753 sata = &dev->sata_dev;
754 if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
755 continue;
756
757 sata->pm_result = -EIO;
758 ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
759 }
760 mutex_unlock(&port->ha->disco_mutex);
761
762 if (sas_ata_flush_pm_eh(port, __func__))
763 goto retry;
764}
765
766void sas_resume_sata(struct asd_sas_port *port)
767{
768 struct domain_device *dev;
769
770 retry:
771 mutex_lock(&port->ha->disco_mutex);
772 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
773 struct sata_device *sata;
774
775 if (!dev_is_sata(dev))
776 continue;
777
778 sata = &dev->sata_dev;
779 if (sata->ap->pm_mesg.event == PM_EVENT_ON)
780 continue;
781
782 sata->pm_result = -EIO;
783 ata_sas_port_async_resume(sata->ap, &sata->pm_result);
784 }
785 mutex_unlock(&port->ha->disco_mutex);
786
787 if (sas_ata_flush_pm_eh(port, __func__))
788 goto retry;
703} 789}
704 790
705/** 791/**
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 3e9dc1a84358..a0c3003e0c7d 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -24,6 +24,7 @@
24 24
25#include <linux/scatterlist.h> 25#include <linux/scatterlist.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/async.h>
27#include <scsi/scsi_host.h> 28#include <scsi/scsi_host.h>
28#include <scsi/scsi_eh.h> 29#include <scsi/scsi_eh.h>
29#include "sas_internal.h" 30#include "sas_internal.h"
@@ -180,16 +181,18 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
180 struct Scsi_Host *shost = sas_ha->core.shost; 181 struct Scsi_Host *shost = sas_ha->core.shost;
181 struct sas_internal *i = to_sas_internal(shost->transportt); 182 struct sas_internal *i = to_sas_internal(shost->transportt);
182 183
183 if (i->dft->lldd_dev_found) { 184 if (!i->dft->lldd_dev_found)
184 res = i->dft->lldd_dev_found(dev); 185 return 0;
185 if (res) { 186
186 printk("sas: driver on pcidev %s cannot handle " 187 res = i->dft->lldd_dev_found(dev);
187 "device %llx, error:%d\n", 188 if (res) {
188 dev_name(sas_ha->dev), 189 printk("sas: driver on pcidev %s cannot handle "
189 SAS_ADDR(dev->sas_addr), res); 190 "device %llx, error:%d\n",
190 } 191 dev_name(sas_ha->dev),
191 kref_get(&dev->kref); 192 SAS_ADDR(dev->sas_addr), res);
192 } 193 }
194 set_bit(SAS_DEV_FOUND, &dev->state);
195 kref_get(&dev->kref);
193 return res; 196 return res;
194} 197}
195 198
@@ -200,7 +203,10 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
200 struct Scsi_Host *shost = sas_ha->core.shost; 203 struct Scsi_Host *shost = sas_ha->core.shost;
201 struct sas_internal *i = to_sas_internal(shost->transportt); 204 struct sas_internal *i = to_sas_internal(shost->transportt);
202 205
203 if (i->dft->lldd_dev_gone) { 206 if (!i->dft->lldd_dev_gone)
207 return;
208
209 if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
204 i->dft->lldd_dev_gone(dev); 210 i->dft->lldd_dev_gone(dev);
205 sas_put_device(dev); 211 sas_put_device(dev);
206 } 212 }
@@ -234,6 +240,47 @@ static void sas_probe_devices(struct work_struct *work)
234 } 240 }
235} 241}
236 242
243static void sas_suspend_devices(struct work_struct *work)
244{
245 struct asd_sas_phy *phy;
246 struct domain_device *dev;
247 struct sas_discovery_event *ev = to_sas_discovery_event(work);
248 struct asd_sas_port *port = ev->port;
249 struct Scsi_Host *shost = port->ha->core.shost;
250 struct sas_internal *si = to_sas_internal(shost->transportt);
251
252 clear_bit(DISCE_SUSPEND, &port->disc.pending);
253
254 sas_suspend_sata(port);
255
256 /* lldd is free to forget the domain_device across the
257 * suspension, we force the issue here to keep the reference
258 * counts aligned
259 */
260 list_for_each_entry(dev, &port->dev_list, dev_list_node)
261 sas_notify_lldd_dev_gone(dev);
262
263 /* we are suspending, so we know events are disabled and
264 * phy_list is not being mutated
265 */
266 list_for_each_entry(phy, &port->phy_list, port_phy_el) {
267 if (si->dft->lldd_port_formed)
268 si->dft->lldd_port_deformed(phy);
269 phy->suspended = 1;
270 port->suspended = 1;
271 }
272}
273
274static void sas_resume_devices(struct work_struct *work)
275{
276 struct sas_discovery_event *ev = to_sas_discovery_event(work);
277 struct asd_sas_port *port = ev->port;
278
279 clear_bit(DISCE_RESUME, &port->disc.pending);
280
281 sas_resume_sata(port);
282}
283
237/** 284/**
238 * sas_discover_end_dev -- discover an end device (SSP, etc) 285 * sas_discover_end_dev -- discover an end device (SSP, etc)
239 * @end: pointer to domain device of interest 286 * @end: pointer to domain device of interest
@@ -530,6 +577,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
530 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, 577 [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
531 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, 578 [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
532 [DISCE_PROBE] = sas_probe_devices, 579 [DISCE_PROBE] = sas_probe_devices,
580 [DISCE_SUSPEND] = sas_suspend_devices,
581 [DISCE_RESUME] = sas_resume_devices,
533 [DISCE_DESTRUCT] = sas_destruct_devices, 582 [DISCE_DESTRUCT] = sas_destruct_devices,
534 }; 583 };
535 584
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index fc460933575c..cd6f99c1ae7e 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[] = {
41 [1] = "PHYE_OOB_DONE", 41 [1] = "PHYE_OOB_DONE",
42 [2] = "PHYE_OOB_ERROR", 42 [2] = "PHYE_OOB_ERROR",
43 [3] = "PHYE_SPINUP_HOLD", 43 [3] = "PHYE_SPINUP_HOLD",
44 [4] = "PHYE_RESUME_TIMEOUT",
44}; 45};
45 46
46void sas_dprint_porte(int phyid, enum port_event pe) 47void 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 789c4d8bb7a7..aadbd5314c5c 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)
134 &phy->port_events[event].work, ha); 134 &phy->port_events[event].work, ha);
135} 135}
136 136
137static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) 137void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
138{ 138{
139 struct sas_ha_struct *ha = phy->ha; 139 struct sas_ha_struct *ha = phy->ha;
140 140
@@ -159,7 +159,7 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
159 159
160 sas_ha->notify_ha_event = notify_ha_event; 160 sas_ha->notify_ha_event = notify_ha_event;
161 sas_ha->notify_port_event = notify_port_event; 161 sas_ha->notify_port_event = notify_port_event;
162 sas_ha->notify_phy_event = notify_phy_event; 162 sas_ha->notify_phy_event = sas_notify_phy_event;
163 163
164 return 0; 164 return 0;
165} 165}
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 014297c05880..dbc8a793fd86 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -178,7 +178,7 @@ Undo_phys:
178 return error; 178 return error;
179} 179}
180 180
181int sas_unregister_ha(struct sas_ha_struct *sas_ha) 181static void sas_disable_events(struct sas_ha_struct *sas_ha)
182{ 182{
183 /* Set the state to unregistered to avoid further unchained 183 /* Set the state to unregistered to avoid further unchained
184 * events to be queued, and flush any in-progress drainers 184 * events to be queued, and flush any in-progress drainers
@@ -189,7 +189,11 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
189 spin_unlock_irq(&sas_ha->lock); 189 spin_unlock_irq(&sas_ha->lock);
190 __sas_drain_work(sas_ha); 190 __sas_drain_work(sas_ha);
191 mutex_unlock(&sas_ha->drain_mutex); 191 mutex_unlock(&sas_ha->drain_mutex);
192}
192 193
194int sas_unregister_ha(struct sas_ha_struct *sas_ha)
195{
196 sas_disable_events(sas_ha);
193 sas_unregister_ports(sas_ha); 197 sas_unregister_ports(sas_ha);
194 198
195 /* flush unregistration work */ 199 /* flush unregistration work */
@@ -381,6 +385,90 @@ int sas_set_phy_speed(struct sas_phy *phy,
381 return ret; 385 return ret;
382} 386}
383 387
388void sas_prep_resume_ha(struct sas_ha_struct *ha)
389{
390 int i;
391
392 set_bit(SAS_HA_REGISTERED, &ha->state);
393
394 /* clear out any stale link events/data from the suspension path */
395 for (i = 0; i < ha->num_phys; i++) {
396 struct asd_sas_phy *phy = ha->sas_phy[i];
397
398 memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
399 phy->port_events_pending = 0;
400 phy->phy_events_pending = 0;
401 phy->frame_rcvd_size = 0;
402 }
403}
404EXPORT_SYMBOL(sas_prep_resume_ha);
405
406static int phys_suspended(struct sas_ha_struct *ha)
407{
408 int i, rc = 0;
409
410 for (i = 0; i < ha->num_phys; i++) {
411 struct asd_sas_phy *phy = ha->sas_phy[i];
412
413 if (phy->suspended)
414 rc++;
415 }
416
417 return rc;
418}
419
420void sas_resume_ha(struct sas_ha_struct *ha)
421{
422 const unsigned long tmo = msecs_to_jiffies(25000);
423 int i;
424
425 /* deform ports on phys that did not resume
426 * at this point we may be racing the phy coming back (as posted
427 * by the lldd). So we post the event and once we are in the
428 * libsas context check that the phy remains suspended before
429 * tearing it down.
430 */
431 i = phys_suspended(ha);
432 if (i)
433 dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
434 i, i > 1 ? "s" : "");
435 wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
436 for (i = 0; i < ha->num_phys; i++) {
437 struct asd_sas_phy *phy = ha->sas_phy[i];
438
439 if (phy->suspended) {
440 dev_warn(&phy->phy->dev, "resume timeout\n");
441 sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT);
442 }
443 }
444
445 /* all phys are back up or timed out, turn on i/o so we can
446 * flush out disks that did not return
447 */
448 scsi_unblock_requests(ha->core.shost);
449 sas_drain_work(ha);
450}
451EXPORT_SYMBOL(sas_resume_ha);
452
453void sas_suspend_ha(struct sas_ha_struct *ha)
454{
455 int i;
456
457 sas_disable_events(ha);
458 scsi_block_requests(ha->core.shost);
459 for (i = 0; i < ha->num_phys; i++) {
460 struct asd_sas_port *port = ha->sas_port[i];
461
462 sas_discover_event(port, DISCE_SUSPEND);
463 }
464
465 /* flush suspend events while unregistered */
466 mutex_lock(&ha->drain_mutex);
467 __sas_drain_work(ha);
468 mutex_unlock(&ha->drain_mutex);
469}
470EXPORT_SYMBOL(sas_suspend_ha);
471
384static void sas_phy_release(struct sas_phy *phy) 472static void sas_phy_release(struct sas_phy *phy)
385{ 473{
386 kfree(phy->hostdata); 474 kfree(phy->hostdata);
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 507e4cf12e56..1de67964e5a1 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -89,6 +89,7 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
89 enum phy_func phy_func, struct sas_phy_linkrates *); 89 enum phy_func phy_func, struct sas_phy_linkrates *);
90int sas_smp_get_phy_events(struct sas_phy *phy); 90int sas_smp_get_phy_events(struct sas_phy *phy);
91 91
92void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
92void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); 93void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
93struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); 94struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
94struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); 95struct 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 521422e857ab..cdee446c29e1 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)
94 i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); 94 i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
95} 95}
96 96
97static void sas_phye_resume_timeout(struct work_struct *work)
98{
99 struct asd_sas_event *ev = to_asd_sas_event(work);
100 struct asd_sas_phy *phy = ev->phy;
101
102 clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
103
104 /* phew, lldd got the phy back in the nick of time */
105 if (!phy->suspended) {
106 dev_info(&phy->phy->dev, "resume timeout cancelled\n");
107 return;
108 }
109
110 phy->error = 0;
111 phy->suspended = 0;
112 sas_deform_port(phy, 1);
113}
114
115
97/* ---------- Phy class registration ---------- */ 116/* ---------- Phy class registration ---------- */
98 117
99int sas_register_phys(struct sas_ha_struct *sas_ha) 118int sas_register_phys(struct sas_ha_struct *sas_ha)
@@ -105,6 +124,8 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
105 [PHYE_OOB_DONE] = sas_phye_oob_done, 124 [PHYE_OOB_DONE] = sas_phye_oob_done,
106 [PHYE_OOB_ERROR] = sas_phye_oob_error, 125 [PHYE_OOB_ERROR] = sas_phye_oob_error,
107 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, 126 [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
127 [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
128
108 }; 129 };
109 130
110 static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { 131 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 e884a8c58a0c..1398b714c018 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
39 return true; 39 return true;
40} 40}
41 41
42static void sas_resume_port(struct asd_sas_phy *phy)
43{
44 struct domain_device *dev;
45 struct asd_sas_port *port = phy->port;
46 struct sas_ha_struct *sas_ha = phy->ha;
47 struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt);
48
49 if (si->dft->lldd_port_formed)
50 si->dft->lldd_port_formed(phy);
51
52 if (port->suspended)
53 port->suspended = 0;
54 else {
55 /* we only need to handle "link returned" actions once */
56 return;
57 }
58
59 /* if the port came back:
60 * 1/ presume every device came back
61 * 2/ force the next revalidation to check all expander phys
62 */
63 list_for_each_entry(dev, &port->dev_list, dev_list_node) {
64 int i, rc;
65
66 rc = sas_notify_lldd_dev_found(dev);
67 if (rc) {
68 sas_unregister_dev(port, dev);
69 continue;
70 }
71
72 if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
73 dev->ex_dev.ex_change_count = -1;
74 for (i = 0; i < dev->ex_dev.num_phys; i++) {
75 struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
76
77 phy->phy_change_count = -1;
78 }
79 }
80 }
81
82 sas_discover_event(port, DISCE_RESUME);
83}
84
42/** 85/**
43 * sas_form_port -- add this phy to a port 86 * sas_form_port -- add this phy to a port
44 * @phy: the phy of interest 87 * @phy: the phy of interest
@@ -58,7 +101,14 @@ static void sas_form_port(struct asd_sas_phy *phy)
58 if (port) { 101 if (port) {
59 if (!phy_is_wideport_member(port, phy)) 102 if (!phy_is_wideport_member(port, phy))
60 sas_deform_port(phy, 0); 103 sas_deform_port(phy, 0);
61 else { 104 else if (phy->suspended) {
105 phy->suspended = 0;
106 sas_resume_port(phy);
107
108 /* phy came back, try to cancel the timeout */
109 wake_up(&sas_ha->eh_wait_q);
110 return;
111 } else {
62 SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", 112 SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
63 __func__, phy->id, phy->port->id, 113 __func__, phy->id, phy->port->id,
64 phy->port->num_phys); 114 phy->port->num_phys);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index ae33706afeb0..ef937b56f9b5 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -79,7 +79,8 @@ enum phy_event {
79 PHYE_OOB_DONE = 1, 79 PHYE_OOB_DONE = 1,
80 PHYE_OOB_ERROR = 2, 80 PHYE_OOB_ERROR = 2,
81 PHYE_SPINUP_HOLD = 3, /* hot plug SATA, no COMWAKE sent */ 81 PHYE_SPINUP_HOLD = 3, /* hot plug SATA, no COMWAKE sent */
82 PHY_NUM_EVENTS = 4, 82 PHYE_RESUME_TIMEOUT = 4,
83 PHY_NUM_EVENTS = 5,
83}; 84};
84 85
85enum discover_event { 86enum discover_event {
@@ -87,8 +88,10 @@ enum discover_event {
87 DISCE_REVALIDATE_DOMAIN = 1, 88 DISCE_REVALIDATE_DOMAIN = 1,
88 DISCE_PORT_GONE = 2, 89 DISCE_PORT_GONE = 2,
89 DISCE_PROBE = 3, 90 DISCE_PROBE = 3,
90 DISCE_DESTRUCT = 4, 91 DISCE_SUSPEND = 4,
91 DISC_NUM_EVENTS = 5, 92 DISCE_RESUME = 5,
93 DISCE_DESTRUCT = 6,
94 DISC_NUM_EVENTS = 7,
92}; 95};
93 96
94/* ---------- Expander Devices ---------- */ 97/* ---------- Expander Devices ---------- */
@@ -128,7 +131,7 @@ struct ex_phy {
128 u8 attached_sas_addr[SAS_ADDR_SIZE]; 131 u8 attached_sas_addr[SAS_ADDR_SIZE];
129 u8 attached_phy_id; 132 u8 attached_phy_id;
130 133
131 u8 phy_change_count; 134 int phy_change_count;
132 enum routing_attribute routing_attr; 135 enum routing_attribute routing_attr;
133 u8 virtual:1; 136 u8 virtual:1;
134 137
@@ -141,7 +144,7 @@ struct ex_phy {
141struct expander_device { 144struct expander_device {
142 struct list_head children; 145 struct list_head children;
143 146
144 u16 ex_change_count; 147 int ex_change_count;
145 u16 max_route_indexes; 148 u16 max_route_indexes;
146 u8 num_phys; 149 u8 num_phys;
147 150
@@ -169,6 +172,7 @@ struct sata_device {
169 enum ata_command_set command_set; 172 enum ata_command_set command_set;
170 struct smp_resp rps_resp; /* report_phy_sata_resp */ 173 struct smp_resp rps_resp; /* report_phy_sata_resp */
171 u8 port_no; /* port number, if this is a PM (Port) */ 174 u8 port_no; /* port number, if this is a PM (Port) */
175 int pm_result;
172 176
173 struct ata_port *ap; 177 struct ata_port *ap;
174 struct ata_host ata_host; 178 struct ata_host ata_host;
@@ -182,6 +186,7 @@ struct ssp_device {
182 186
183enum { 187enum {
184 SAS_DEV_GONE, 188 SAS_DEV_GONE,
189 SAS_DEV_FOUND, /* device notified to lldd */
185 SAS_DEV_DESTROY, 190 SAS_DEV_DESTROY,
186 SAS_DEV_EH_PENDING, 191 SAS_DEV_EH_PENDING,
187 SAS_DEV_LU_RESET, 192 SAS_DEV_LU_RESET,
@@ -273,6 +278,7 @@ struct asd_sas_port {
273 enum sas_linkrate linkrate; 278 enum sas_linkrate linkrate;
274 279
275 struct sas_work work; 280 struct sas_work work;
281 int suspended;
276 282
277/* public: */ 283/* public: */
278 int id; 284 int id;
@@ -321,6 +327,7 @@ struct asd_sas_phy {
321 unsigned long phy_events_pending; 327 unsigned long phy_events_pending;
322 328
323 int error; 329 int error;
330 int suspended;
324 331
325 struct sas_phy *phy; 332 struct sas_phy *phy;
326 333
@@ -687,6 +694,9 @@ struct sas_domain_function_template {
687 694
688extern int sas_register_ha(struct sas_ha_struct *); 695extern int sas_register_ha(struct sas_ha_struct *);
689extern int sas_unregister_ha(struct sas_ha_struct *); 696extern int sas_unregister_ha(struct sas_ha_struct *);
697extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha);
698extern void sas_resume_ha(struct sas_ha_struct *sas_ha);
699extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
690 700
691int sas_set_phy_speed(struct sas_phy *phy, 701int sas_set_phy_speed(struct sas_phy *phy,
692 struct sas_phy_linkrates *rates); 702 struct sas_phy_linkrates *rates);
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
index 2dfbdaa0b34a..ff71a5654684 100644
--- a/include/scsi/sas_ata.h
+++ b/include/scsi/sas_ata.h
@@ -45,6 +45,8 @@ void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
45void sas_ata_schedule_reset(struct domain_device *dev); 45void sas_ata_schedule_reset(struct domain_device *dev);
46void sas_ata_wait_eh(struct domain_device *dev); 46void sas_ata_wait_eh(struct domain_device *dev);
47void sas_probe_sata(struct asd_sas_port *port); 47void sas_probe_sata(struct asd_sas_port *port);
48void sas_suspend_sata(struct asd_sas_port *port);
49void sas_resume_sata(struct asd_sas_port *port);
48void sas_ata_end_eh(struct ata_port *ap); 50void sas_ata_end_eh(struct ata_port *ap);
49#else 51#else
50 52
@@ -82,6 +84,14 @@ static inline void sas_probe_sata(struct asd_sas_port *port)
82{ 84{
83} 85}
84 86
87static inline void sas_suspend_sata(struct asd_sas_port *port)
88{
89}
90
91static inline void sas_resume_sata(struct asd_sas_port *port)
92{
93}
94
85static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) 95static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
86{ 96{
87 return 0; 97 return 0;