aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2013-01-15 04:21:01 -0500
committerJeff Garzik <jgarzik@redhat.com>2013-01-21 15:41:56 -0500
commit213342053db58eabdaddff9c036c2b81ca63c443 (patch)
treee6c8b474717496289a5cbc3674e639f4814f784a /drivers/ata
parent3dc67440d99b2c718ef5f1eb1424a9066ffa3fb9 (diff)
libata: handle power transition of ODD
When ata port is runtime suspended, it will check if the ODD attched to it is a zero power(ZP) capable ODD and if the ZP capable ODD is in zero power ready state. And if this is not the case, the highest acpi state will be limited to ACPI_STATE_D3_HOT to avoid powering off the ODD. And if the ODD can be powered off, runtime wake capability needs to be enabled and powered_off flag will be set to let resume code knows that the ODD was in powered off state. And on resume, before it is powered on, if it was powered off during suspend, runtime wake capability needs to be disabled. After it is recovered, the ODD is considered functional, post power on processing like eject tray if the ODD is drawer type is done, and several ZPODD related fields will also be reset. Signed-off-by: Aaron Lu <aaron.lu@intel.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/libata-acpi.c35
-rw-r--r--drivers/ata/libata-eh.c2
-rw-r--r--drivers/ata/libata-zpodd.c83
-rw-r--r--drivers/ata/libata.h8
4 files changed, 118 insertions, 10 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 446b4e761af0..6f72c648ea14 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -835,6 +835,22 @@ void ata_acpi_on_resume(struct ata_port *ap)
835 } 835 }
836} 836}
837 837
838static int ata_acpi_choose_suspend_state(struct ata_device *dev)
839{
840 int d_max_in = ACPI_STATE_D3_COLD;
841
842 /*
843 * For ATAPI, runtime D3 cold is only allowed
844 * for ZPODD in zero power ready state
845 */
846 if (dev->class == ATA_DEV_ATAPI &&
847 !(zpodd_dev_enabled(dev) && zpodd_zpready(dev)))
848 d_max_in = ACPI_STATE_D3_HOT;
849
850 return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev,
851 NULL, d_max_in);
852}
853
838/** 854/**
839 * ata_acpi_set_state - set the port power state 855 * ata_acpi_set_state - set the port power state
840 * @ap: target ATA port 856 * @ap: target ATA port
@@ -861,17 +877,16 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
861 continue; 877 continue;
862 878
863 if (state.event != PM_EVENT_ON) { 879 if (state.event != PM_EVENT_ON) {
864 acpi_state = acpi_pm_device_sleep_state( 880 acpi_state = ata_acpi_choose_suspend_state(dev);
865 &dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3); 881 if (acpi_state == ACPI_STATE_D0)
866 if (acpi_state > 0) 882 continue;
867 acpi_bus_set_power(handle, acpi_state); 883 if (zpodd_dev_enabled(dev) &&
868 /* TBD: need to check if it's runtime pm request */ 884 acpi_state == ACPI_STATE_D3_COLD)
869 acpi_pm_device_run_wake( 885 zpodd_enable_run_wake(dev);
870 &dev->sdev->sdev_gendev, true); 886 acpi_bus_set_power(handle, acpi_state);
871 } else { 887 } else {
872 /* Ditto */ 888 if (zpodd_dev_enabled(dev))
873 acpi_pm_device_run_wake( 889 zpodd_disable_run_wake(dev);
874 &dev->sdev->sdev_gendev, false);
875 acpi_bus_set_power(handle, ACPI_STATE_D0); 890 acpi_bus_set_power(handle, ACPI_STATE_D0);
876 } 891 }
877 } 892 }
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a0dddc3b4924..50f3ef04809d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -3857,6 +3857,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
3857 rc = atapi_eh_clear_ua(dev); 3857 rc = atapi_eh_clear_ua(dev);
3858 if (rc) 3858 if (rc)
3859 goto rest_fail; 3859 goto rest_fail;
3860 if (zpodd_dev_enabled(dev))
3861 zpodd_post_poweron(dev);
3860 } 3862 }
3861 } 3863 }
3862 3864
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
index 71dd48c94f2c..1f5d52ae3974 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -26,8 +26,26 @@ struct zpodd {
26 bool zp_ready; /* ZP ready state */ 26 bool zp_ready; /* ZP ready state */
27 unsigned long last_ready; /* last ZP ready timestamp */ 27 unsigned long last_ready; /* last ZP ready timestamp */
28 bool zp_sampled; /* ZP ready state sampled */ 28 bool zp_sampled; /* ZP ready state sampled */
29 bool powered_off; /* ODD is powered off
30 * during suspend */
29}; 31};
30 32
33static int eject_tray(struct ata_device *dev)
34{
35 struct ata_taskfile tf = {};
36 const char cdb[] = { GPCMD_START_STOP_UNIT,
37 0, 0, 0,
38 0x02, /* LoEj */
39 0, 0, 0, 0, 0, 0, 0,
40 };
41
42 tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
43 tf.command = ATA_CMD_PACKET;
44 tf.protocol = ATAPI_PROT_NODATA;
45
46 return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
47}
48
31/* Per the spec, only slot type and drawer type ODD can be supported */ 49/* Per the spec, only slot type and drawer type ODD can be supported */
32static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) 50static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
33{ 51{
@@ -149,6 +167,71 @@ void zpodd_on_suspend(struct ata_device *dev)
149 zpodd->zp_ready = true; 167 zpodd->zp_ready = true;
150} 168}
151 169
170bool zpodd_zpready(struct ata_device *dev)
171{
172 struct zpodd *zpodd = dev->zpodd;
173 return zpodd->zp_ready;
174}
175
176/*
177 * Enable runtime wake capability through ACPI and set the powered_off flag,
178 * this flag will be used during resume to decide what operations are needed
179 * to take.
180 */
181void zpodd_enable_run_wake(struct ata_device *dev)
182{
183 struct zpodd *zpodd = dev->zpodd;
184
185 zpodd->powered_off = true;
186 device_set_run_wake(&dev->sdev->sdev_gendev, true);
187 acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true);
188}
189
190/* Disable runtime wake capability if it is enabled */
191void zpodd_disable_run_wake(struct ata_device *dev)
192{
193 struct zpodd *zpodd = dev->zpodd;
194
195 if (zpodd->powered_off) {
196 acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false);
197 device_set_run_wake(&dev->sdev->sdev_gendev, false);
198 }
199}
200
201/*
202 * Post power on processing after the ODD has been recovered. If the
203 * ODD wasn't powered off during suspend, it doesn't do anything.
204 *
205 * For drawer type ODD, if it is powered on due to user pressed the
206 * eject button, the tray needs to be ejected. This can only be done
207 * after the ODD has been recovered, i.e. link is initialized and
208 * device is able to process NON_DATA PIO command, as eject needs to
209 * send command for the ODD to process.
210 *
211 * The from_notify flag set in wake notification handler function
212 * zpodd_wake_dev represents if power on is due to user's action.
213 *
214 * For both types of ODD, several fields need to be reset.
215 */
216void zpodd_post_poweron(struct ata_device *dev)
217{
218 struct zpodd *zpodd = dev->zpodd;
219
220 if (!zpodd->powered_off)
221 return;
222
223 zpodd->powered_off = false;
224
225 if (zpodd->from_notify) {
226 zpodd->from_notify = false;
227 if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER)
228 eject_tray(dev);
229 }
230
231 zpodd->zp_sampled = false;
232 zpodd->zp_ready = false;
233}
234
152static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) 235static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
153{ 236{
154 struct ata_device *ata_dev = context; 237 struct ata_device *ata_dev = context;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index b9b2bb1d5dc6..c949dd311b2e 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -242,11 +242,19 @@ static inline bool zpodd_dev_enabled(struct ata_device *dev)
242 return dev->zpodd != NULL; 242 return dev->zpodd != NULL;
243} 243}
244void zpodd_on_suspend(struct ata_device *dev); 244void zpodd_on_suspend(struct ata_device *dev);
245bool zpodd_zpready(struct ata_device *dev);
246void zpodd_enable_run_wake(struct ata_device *dev);
247void zpodd_disable_run_wake(struct ata_device *dev);
248void zpodd_post_poweron(struct ata_device *dev);
245#else /* CONFIG_SATA_ZPODD */ 249#else /* CONFIG_SATA_ZPODD */
246static inline void zpodd_init(struct ata_device *dev) {} 250static inline void zpodd_init(struct ata_device *dev) {}
247static inline void zpodd_exit(struct ata_device *dev) {} 251static inline void zpodd_exit(struct ata_device *dev) {}
248static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; } 252static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; }
249static inline void zpodd_on_suspend(struct ata_device *dev) {} 253static inline void zpodd_on_suspend(struct ata_device *dev) {}
254static inline bool zpodd_zpready(struct ata_device *dev) { return false; }
255static inline void zpodd_enable_run_wake(struct ata_device *dev) {}
256static inline void zpodd_disable_run_wake(struct ata_device *dev) {}
257static inline void zpodd_post_poweron(struct ata_device *dev) {}
250#endif /* CONFIG_SATA_ZPODD */ 258#endif /* CONFIG_SATA_ZPODD */
251 259
252#endif /* __LIBATA_H__ */ 260#endif /* __LIBATA_H__ */