diff options
author | Jens Axboe <axboe@suse.de> | 2006-01-06 03:28:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:36:09 -0500 |
commit | 9b847548663ef1039dd49f0eb4463d001e596bc3 (patch) | |
tree | 105a0eece522b1347bea57f609f6c04ed673fdb3 /drivers/scsi/libata-core.c | |
parent | 88202a0c84e1951d6630d1d557d4801a8cc5b5ef (diff) |
[PATCH] Suspend support for libata
This patch adds suspend patch to libata, and ata_piix in particular. For
most low level drivers, they should just need to add the 4 hooks to
work. As I can only test ata_piix, I didn't enable it for more
though.
Suspend support is the single most important feature on a notebook, and
most new notebooks have sata drives. It's quite embarrassing that we
_still_ do not support this. Right now, it's perfectly possible to
suspend the drive in mid-transfer.
Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r-- | drivers/scsi/libata-core.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 9ea102587914..9c66d4059399 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c | |||
@@ -4154,6 +4154,96 @@ err_out: | |||
4154 | * Inherited from caller. | 4154 | * Inherited from caller. |
4155 | */ | 4155 | */ |
4156 | 4156 | ||
4157 | /* | ||
4158 | * Execute a 'simple' command, that only consists of the opcode 'cmd' itself, | ||
4159 | * without filling any other registers | ||
4160 | */ | ||
4161 | static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev, | ||
4162 | u8 cmd) | ||
4163 | { | ||
4164 | struct ata_taskfile tf; | ||
4165 | int err; | ||
4166 | |||
4167 | ata_tf_init(ap, &tf, dev->devno); | ||
4168 | |||
4169 | tf.command = cmd; | ||
4170 | tf.flags |= ATA_TFLAG_DEVICE; | ||
4171 | tf.protocol = ATA_PROT_NODATA; | ||
4172 | |||
4173 | err = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0); | ||
4174 | if (err) | ||
4175 | printk(KERN_ERR "%s: ata command failed: %d\n", | ||
4176 | __FUNCTION__, err); | ||
4177 | |||
4178 | return err; | ||
4179 | } | ||
4180 | |||
4181 | static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev) | ||
4182 | { | ||
4183 | u8 cmd; | ||
4184 | |||
4185 | if (!ata_try_flush_cache(dev)) | ||
4186 | return 0; | ||
4187 | |||
4188 | if (ata_id_has_flush_ext(dev->id)) | ||
4189 | cmd = ATA_CMD_FLUSH_EXT; | ||
4190 | else | ||
4191 | cmd = ATA_CMD_FLUSH; | ||
4192 | |||
4193 | return ata_do_simple_cmd(ap, dev, cmd); | ||
4194 | } | ||
4195 | |||
4196 | static int ata_standby_drive(struct ata_port *ap, struct ata_device *dev) | ||
4197 | { | ||
4198 | return ata_do_simple_cmd(ap, dev, ATA_CMD_STANDBYNOW1); | ||
4199 | } | ||
4200 | |||
4201 | static int ata_start_drive(struct ata_port *ap, struct ata_device *dev) | ||
4202 | { | ||
4203 | return ata_do_simple_cmd(ap, dev, ATA_CMD_IDLEIMMEDIATE); | ||
4204 | } | ||
4205 | |||
4206 | /** | ||
4207 | * ata_device_resume - wakeup a previously suspended devices | ||
4208 | * | ||
4209 | * Kick the drive back into action, by sending it an idle immediate | ||
4210 | * command and making sure its transfer mode matches between drive | ||
4211 | * and host. | ||
4212 | * | ||
4213 | */ | ||
4214 | int ata_device_resume(struct ata_port *ap, struct ata_device *dev) | ||
4215 | { | ||
4216 | if (ap->flags & ATA_FLAG_SUSPENDED) { | ||
4217 | ap->flags &= ~ATA_FLAG_SUSPENDED; | ||
4218 | ata_set_mode(ap); | ||
4219 | } | ||
4220 | if (!ata_dev_present(dev)) | ||
4221 | return 0; | ||
4222 | if (dev->class == ATA_DEV_ATA) | ||
4223 | ata_start_drive(ap, dev); | ||
4224 | |||
4225 | return 0; | ||
4226 | } | ||
4227 | |||
4228 | /** | ||
4229 | * ata_device_suspend - prepare a device for suspend | ||
4230 | * | ||
4231 | * Flush the cache on the drive, if appropriate, then issue a | ||
4232 | * standbynow command. | ||
4233 | * | ||
4234 | */ | ||
4235 | int ata_device_suspend(struct ata_port *ap, struct ata_device *dev) | ||
4236 | { | ||
4237 | if (!ata_dev_present(dev)) | ||
4238 | return 0; | ||
4239 | if (dev->class == ATA_DEV_ATA) | ||
4240 | ata_flush_cache(ap, dev); | ||
4241 | |||
4242 | ata_standby_drive(ap, dev); | ||
4243 | ap->flags |= ATA_FLAG_SUSPENDED; | ||
4244 | return 0; | ||
4245 | } | ||
4246 | |||
4157 | int ata_port_start (struct ata_port *ap) | 4247 | int ata_port_start (struct ata_port *ap) |
4158 | { | 4248 | { |
4159 | struct device *dev = ap->host_set->dev; | 4249 | struct device *dev = ap->host_set->dev; |
@@ -4902,6 +4992,23 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) | |||
4902 | 4992 | ||
4903 | return (tmp == bits->val) ? 1 : 0; | 4993 | return (tmp == bits->val) ? 1 : 0; |
4904 | } | 4994 | } |
4995 | |||
4996 | int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state) | ||
4997 | { | ||
4998 | pci_save_state(pdev); | ||
4999 | pci_disable_device(pdev); | ||
5000 | pci_set_power_state(pdev, PCI_D3hot); | ||
5001 | return 0; | ||
5002 | } | ||
5003 | |||
5004 | int ata_pci_device_resume(struct pci_dev *pdev) | ||
5005 | { | ||
5006 | pci_set_power_state(pdev, PCI_D0); | ||
5007 | pci_restore_state(pdev); | ||
5008 | pci_enable_device(pdev); | ||
5009 | pci_set_master(pdev); | ||
5010 | return 0; | ||
5011 | } | ||
4905 | #endif /* CONFIG_PCI */ | 5012 | #endif /* CONFIG_PCI */ |
4906 | 5013 | ||
4907 | 5014 | ||
@@ -5005,4 +5112,11 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop); | |||
5005 | EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); | 5112 | EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); |
5006 | EXPORT_SYMBOL_GPL(ata_pci_init_one); | 5113 | EXPORT_SYMBOL_GPL(ata_pci_init_one); |
5007 | EXPORT_SYMBOL_GPL(ata_pci_remove_one); | 5114 | EXPORT_SYMBOL_GPL(ata_pci_remove_one); |
5115 | EXPORT_SYMBOL_GPL(ata_pci_device_suspend); | ||
5116 | EXPORT_SYMBOL_GPL(ata_pci_device_resume); | ||
5008 | #endif /* CONFIG_PCI */ | 5117 | #endif /* CONFIG_PCI */ |
5118 | |||
5119 | EXPORT_SYMBOL_GPL(ata_device_suspend); | ||
5120 | EXPORT_SYMBOL_GPL(ata_device_resume); | ||
5121 | EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); | ||
5122 | EXPORT_SYMBOL_GPL(ata_scsi_device_resume); | ||