1#include <linux/libata.h>
2#include <linux/cdrom.h>
3#include <linux/pm_runtime.h>
4#include <linux/module.h>
5#include <linux/pm_qos.h>
6#include <scsi/scsi_device.h>
7
8#include "libata.h"
9
10static int zpodd_poweroff_delay = 30; /* 30 seconds for power off delay */
11module_param(zpodd_poweroff_delay, int, 0644);
12MODULE_PARM_DESC(zpodd_poweroff_delay, "Poweroff delay for ZPODD in seconds");
13
14enum odd_mech_type {
15	ODD_MECH_TYPE_SLOT,
16	ODD_MECH_TYPE_DRAWER,
17	ODD_MECH_TYPE_UNSUPPORTED,
18};
19
20struct zpodd {
21	enum odd_mech_type	mech_type; /* init during probe, RO afterwards */
22	struct ata_device	*dev;
23
24	/* The following fields are synchronized by PM core. */
25	bool			from_notify; /* resumed as a result of
26					      * acpi wake notification */
27	bool			zp_ready; /* ZP ready state */
28	unsigned long		last_ready; /* last ZP ready timestamp */
29	bool			zp_sampled; /* ZP ready state sampled */
30	bool			powered_off; /* ODD is powered off
31					      *	during suspend */
32};
33
34static int eject_tray(struct ata_device *dev)
35{
36	struct ata_taskfile tf;
37	const char cdb[] = {  GPCMD_START_STOP_UNIT,
38		0, 0, 0,
39		0x02,     /* LoEj */
40		0, 0, 0, 0, 0, 0, 0,
41	};
42
43	ata_tf_init(dev, &tf);
44	tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
45	tf.command = ATA_CMD_PACKET;
46	tf.protocol = ATAPI_PROT_NODATA;
47
48	return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
49}
50
51/* Per the spec, only slot type and drawer type ODD can be supported */
52static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
53{
54	char buf[16];
55	unsigned int ret;
56	struct rm_feature_desc *desc = (void *)(buf + 8);
57	struct ata_taskfile tf;
58	char cdb[] = {  GPCMD_GET_CONFIGURATION,
59			2,      /* only 1 feature descriptor requested */
60			0, 3,   /* 3, removable medium feature */
61			0, 0, 0,/* reserved */
62			0, sizeof(buf),
63			0, 0, 0,
64	};
65
66	ata_tf_init(dev, &tf);
67	tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
68	tf.command = ATA_CMD_PACKET;
69	tf.protocol = ATAPI_PROT_PIO;
70	tf.lbam = sizeof(buf);
71
72	ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
73				buf, sizeof(buf), 0);
74	if (ret)
75		return ODD_MECH_TYPE_UNSUPPORTED;
76
77	if (be16_to_cpu(desc->feature_code) != 3)
78		return ODD_MECH_TYPE_UNSUPPORTED;
79
80	if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1)
81		return ODD_MECH_TYPE_SLOT;
82	else if (desc->mech_type == 1 && desc->load == 0 && desc->eject == 1)
83		return ODD_MECH_TYPE_DRAWER;
84	else
85		return ODD_MECH_TYPE_UNSUPPORTED;
86}
87
88/* Test if ODD is zero power ready by sense code */
89static bool zpready(struct ata_device *dev)
90{
91	u8 sense_key, *sense_buf;
92	unsigned int ret, asc, ascq, add_len;
93	struct zpodd *zpodd = dev->zpodd;
94
95	ret = atapi_eh_tur(dev, &sense_key);
96
97	if (!ret || sense_key != NOT_READY)
98		return false;
99
100	sense_buf = dev->link->ap->sector_buf;
101	ret = atapi_eh_request_sense(dev, sense_buf, sense_key);
102	if (ret)
103		return false;
104
105	/* sense valid */
106	if ((sense_buf[0] & 0x7f) != 0x70)
107		return false;
108
109	add_len = sense_buf[7];
110	/* has asc and ascq */
111	if (add_len < 6)
112		return false;
113
114	asc = sense_buf[12];
115	ascq = sense_buf[13];
116
117	if (zpodd->mech_type == ODD_MECH_TYPE_SLOT)
118		/* no media inside */
119		return asc == 0x3a;
120	else
121		/* no media inside and door closed */
122		return asc == 0x3a && ascq == 0x01;
123}
124
125/*
126 * Update the zpodd->zp_ready field. This field will only be set
127 * if the ODD has stayed in ZP ready state for zpodd_poweroff_delay
128 * time, and will be used to decide if power off is allowed. If it
129 * is set, it will be cleared during resume from powered off state.
130 */
131void zpodd_on_suspend(struct ata_device *dev)
132{
133	struct zpodd *zpodd = dev->zpodd;
134	unsigned long expires;
135
136	if (!zpready(dev)) {
137		zpodd->zp_sampled = false;
138		zpodd->zp_ready = false;
139		return;
140	}
141
142	if (!zpodd->zp_sampled) {
143		zpodd->zp_sampled = true;
144		zpodd->last_ready = jiffies;
145		return;
146	}
147
148	expires = zpodd->last_ready +
149		  msecs_to_jiffies(zpodd_poweroff_delay * 1000);
150	if (time_before(jiffies, expires))
151		return;
152
153	zpodd->zp_ready = true;
154}
155
156bool zpodd_zpready(struct ata_device *dev)
157{
158	struct zpodd *zpodd = dev->zpodd;
159	return zpodd->zp_ready;
160}
161
162/*
163 * Enable runtime wake capability through ACPI and set the powered_off flag,
164 * this flag will be used during resume to decide what operations are needed
165 * to take.
166 *
167 * Also, media poll needs to be silenced, so that it doesn't bring the ODD
168 * back to full power state every few seconds.
169 */
170void zpodd_enable_run_wake(struct ata_device *dev)
171{
172	struct zpodd *zpodd = dev->zpodd;
173
174	sdev_disable_disk_events(dev->sdev);
175
176	zpodd->powered_off = true;
177	device_set_run_wake(&dev->tdev, true);
178	acpi_pm_device_run_wake(&dev->tdev, true);
179}
180
181/* Disable runtime wake capability if it is enabled */
182void zpodd_disable_run_wake(struct ata_device *dev)
183{
184	struct zpodd *zpodd = dev->zpodd;
185
186	if (zpodd->powered_off) {
187		acpi_pm_device_run_wake(&dev->tdev, false);
188		device_set_run_wake(&dev->tdev, false);
189	}
190}
191
192/*
193 * Post power on processing after the ODD has been recovered. If the
194 * ODD wasn't powered off during suspend, it doesn't do anything.
195 *
196 * For drawer type ODD, if it is powered on due to user pressed the
197 * eject button, the tray needs to be ejected. This can only be done
198 * after the ODD has been recovered, i.e. link is initialized and
199 * device is able to process NON_DATA PIO command, as eject needs to
200 * send command for the ODD to process.
201 *
202 * The from_notify flag set in wake notification handler function
203 * zpodd_wake_dev represents if power on is due to user's action.
204 *
205 * For both types of ODD, several fields need to be reset.
206 */
207void zpodd_post_poweron(struct ata_device *dev)
208{
209	struct zpodd *zpodd = dev->zpodd;
210
211	if (!zpodd->powered_off)
212		return;
213
214	zpodd->powered_off = false;
215
216	if (zpodd->from_notify) {
217		zpodd->from_notify = false;
218		if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER)
219			eject_tray(dev);
220	}
221
222	zpodd->zp_sampled = false;
223	zpodd->zp_ready = false;
224
225	sdev_enable_disk_events(dev->sdev);
226}
227
228static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
229{
230	struct ata_device *ata_dev = context;
231	struct zpodd *zpodd = ata_dev->zpodd;
232	struct device *dev = &ata_dev->sdev->sdev_gendev;
233
234	if (event == ACPI_NOTIFY_DEVICE_WAKE && pm_runtime_suspended(dev)) {
235		zpodd->from_notify = true;
236		pm_runtime_resume(dev);
237	}
238}
239
240static void ata_acpi_add_pm_notifier(struct ata_device *dev)
241{
242	acpi_handle handle = ata_dev_acpi_handle(dev);
243	acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
244				    zpodd_wake_dev, dev);
245}
246
247static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
248{
249	acpi_handle handle = ata_dev_acpi_handle(dev);
250	acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev);
251}
252
253void zpodd_init(struct ata_device *dev)
254{
255	struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
256	enum odd_mech_type mech_type;
257	struct zpodd *zpodd;
258
259	if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
260		return;
261
262	mech_type = zpodd_get_mech_type(dev);
263	if (mech_type == ODD_MECH_TYPE_UNSUPPORTED)
264		return;
265
266	zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL);
267	if (!zpodd)
268		return;
269
270	zpodd->mech_type = mech_type;
271
272	ata_acpi_add_pm_notifier(dev);
273	zpodd->dev = dev;
274	dev->zpodd = zpodd;
275	dev_pm_qos_expose_flags(&dev->tdev, 0);
276}
277
278void zpodd_exit(struct ata_device *dev)
279{
280	ata_acpi_remove_pm_notifier(dev);
281	kfree(dev->zpodd);
282	dev->zpodd = NULL;
283}
284