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