0001
0002 #include <linux/libata.h>
0003 #include <linux/cdrom.h>
0004 #include <linux/pm_runtime.h>
0005 #include <linux/module.h>
0006 #include <linux/pm_qos.h>
0007 #include <scsi/scsi_device.h>
0008
0009 #include "libata.h"
0010
0011 static int zpodd_poweroff_delay = 30;
0012 module_param(zpodd_poweroff_delay, int, 0644);
0013 MODULE_PARM_DESC(zpodd_poweroff_delay, "Poweroff delay for ZPODD in seconds");
0014
0015 enum odd_mech_type {
0016 ODD_MECH_TYPE_SLOT,
0017 ODD_MECH_TYPE_DRAWER,
0018 ODD_MECH_TYPE_UNSUPPORTED,
0019 };
0020
0021 struct zpodd {
0022 enum odd_mech_type mech_type;
0023 struct ata_device *dev;
0024
0025
0026 bool from_notify;
0027
0028 bool zp_ready;
0029 unsigned long last_ready;
0030 bool zp_sampled;
0031 bool powered_off;
0032
0033 };
0034
0035 static int eject_tray(struct ata_device *dev)
0036 {
0037 struct ata_taskfile tf;
0038 static const char cdb[ATAPI_CDB_LEN] = { GPCMD_START_STOP_UNIT,
0039 0, 0, 0,
0040 0x02,
0041 0, 0, 0, 0, 0, 0, 0,
0042 };
0043
0044 ata_tf_init(dev, &tf);
0045 tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
0046 tf.command = ATA_CMD_PACKET;
0047 tf.protocol = ATAPI_PROT_NODATA;
0048
0049 return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
0050 }
0051
0052
0053 static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
0054 {
0055 char *buf;
0056 unsigned int ret;
0057 struct rm_feature_desc *desc;
0058 struct ata_taskfile tf;
0059 static const char cdb[ATAPI_CDB_LEN] = { GPCMD_GET_CONFIGURATION,
0060 2,
0061 0, 3,
0062 0, 0, 0,
0063 0, 16,
0064 0, 0, 0,
0065 };
0066
0067 buf = kzalloc(16, GFP_KERNEL);
0068 if (!buf)
0069 return ODD_MECH_TYPE_UNSUPPORTED;
0070 desc = (void *)(buf + 8);
0071
0072 ata_tf_init(dev, &tf);
0073 tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
0074 tf.command = ATA_CMD_PACKET;
0075 tf.protocol = ATAPI_PROT_PIO;
0076 tf.lbam = 16;
0077
0078 ret = ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
0079 buf, 16, 0);
0080 if (ret) {
0081 kfree(buf);
0082 return ODD_MECH_TYPE_UNSUPPORTED;
0083 }
0084
0085 if (be16_to_cpu(desc->feature_code) != 3) {
0086 kfree(buf);
0087 return ODD_MECH_TYPE_UNSUPPORTED;
0088 }
0089
0090 if (desc->mech_type == 0 && desc->load == 0 && desc->eject == 1) {
0091 kfree(buf);
0092 return ODD_MECH_TYPE_SLOT;
0093 } else if (desc->mech_type == 1 && desc->load == 0 &&
0094 desc->eject == 1) {
0095 kfree(buf);
0096 return ODD_MECH_TYPE_DRAWER;
0097 } else {
0098 kfree(buf);
0099 return ODD_MECH_TYPE_UNSUPPORTED;
0100 }
0101 }
0102
0103
0104 static bool zpready(struct ata_device *dev)
0105 {
0106 u8 sense_key, *sense_buf;
0107 unsigned int ret, asc, ascq, add_len;
0108 struct zpodd *zpodd = dev->zpodd;
0109
0110 ret = atapi_eh_tur(dev, &sense_key);
0111
0112 if (!ret || sense_key != NOT_READY)
0113 return false;
0114
0115 sense_buf = dev->link->ap->sector_buf;
0116 ret = atapi_eh_request_sense(dev, sense_buf, sense_key);
0117 if (ret)
0118 return false;
0119
0120
0121 if ((sense_buf[0] & 0x7f) != 0x70)
0122 return false;
0123
0124 add_len = sense_buf[7];
0125
0126 if (add_len < 6)
0127 return false;
0128
0129 asc = sense_buf[12];
0130 ascq = sense_buf[13];
0131
0132 if (zpodd->mech_type == ODD_MECH_TYPE_SLOT)
0133
0134 return asc == 0x3a;
0135 else
0136
0137 return asc == 0x3a && ascq == 0x01;
0138 }
0139
0140
0141
0142
0143
0144
0145
0146 void zpodd_on_suspend(struct ata_device *dev)
0147 {
0148 struct zpodd *zpodd = dev->zpodd;
0149 unsigned long expires;
0150
0151 if (!zpready(dev)) {
0152 zpodd->zp_sampled = false;
0153 zpodd->zp_ready = false;
0154 return;
0155 }
0156
0157 if (!zpodd->zp_sampled) {
0158 zpodd->zp_sampled = true;
0159 zpodd->last_ready = jiffies;
0160 return;
0161 }
0162
0163 expires = zpodd->last_ready +
0164 msecs_to_jiffies(zpodd_poweroff_delay * 1000);
0165 if (time_before(jiffies, expires))
0166 return;
0167
0168 zpodd->zp_ready = true;
0169 }
0170
0171 bool zpodd_zpready(struct ata_device *dev)
0172 {
0173 struct zpodd *zpodd = dev->zpodd;
0174 return zpodd->zp_ready;
0175 }
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185 void zpodd_enable_run_wake(struct ata_device *dev)
0186 {
0187 struct zpodd *zpodd = dev->zpodd;
0188
0189 sdev_disable_disk_events(dev->sdev);
0190
0191 zpodd->powered_off = true;
0192 acpi_pm_set_device_wakeup(&dev->tdev, true);
0193 }
0194
0195
0196 void zpodd_disable_run_wake(struct ata_device *dev)
0197 {
0198 struct zpodd *zpodd = dev->zpodd;
0199
0200 if (zpodd->powered_off)
0201 acpi_pm_set_device_wakeup(&dev->tdev, false);
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 void zpodd_post_poweron(struct ata_device *dev)
0220 {
0221 struct zpodd *zpodd = dev->zpodd;
0222
0223 if (!zpodd->powered_off)
0224 return;
0225
0226 zpodd->powered_off = false;
0227
0228 if (zpodd->from_notify) {
0229 zpodd->from_notify = false;
0230 if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER)
0231 eject_tray(dev);
0232 }
0233
0234 zpodd->zp_sampled = false;
0235 zpodd->zp_ready = false;
0236
0237 sdev_enable_disk_events(dev->sdev);
0238 }
0239
0240 static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context)
0241 {
0242 struct ata_device *ata_dev = context;
0243 struct zpodd *zpodd = ata_dev->zpodd;
0244 struct device *dev = &ata_dev->sdev->sdev_gendev;
0245
0246 if (event == ACPI_NOTIFY_DEVICE_WAKE && pm_runtime_suspended(dev)) {
0247 zpodd->from_notify = true;
0248 pm_runtime_resume(dev);
0249 }
0250 }
0251
0252 static void ata_acpi_add_pm_notifier(struct ata_device *dev)
0253 {
0254 acpi_handle handle = ata_dev_acpi_handle(dev);
0255 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
0256 zpodd_wake_dev, dev);
0257 }
0258
0259 static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
0260 {
0261 acpi_handle handle = ata_dev_acpi_handle(dev);
0262 acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev);
0263 }
0264
0265 void zpodd_init(struct ata_device *dev)
0266 {
0267 struct acpi_device *adev = ACPI_COMPANION(&dev->tdev);
0268 enum odd_mech_type mech_type;
0269 struct zpodd *zpodd;
0270
0271 if (dev->zpodd || !adev || !acpi_device_can_poweroff(adev))
0272 return;
0273
0274 mech_type = zpodd_get_mech_type(dev);
0275 if (mech_type == ODD_MECH_TYPE_UNSUPPORTED)
0276 return;
0277
0278 zpodd = kzalloc(sizeof(struct zpodd), GFP_KERNEL);
0279 if (!zpodd)
0280 return;
0281
0282 zpodd->mech_type = mech_type;
0283
0284 ata_acpi_add_pm_notifier(dev);
0285 zpodd->dev = dev;
0286 dev->zpodd = zpodd;
0287 dev_pm_qos_expose_flags(&dev->tdev, 0);
0288 }
0289
0290 void zpodd_exit(struct ata_device *dev)
0291 {
0292 ata_acpi_remove_pm_notifier(dev);
0293 kfree(dev->zpodd);
0294 dev->zpodd = NULL;
0295 }