aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ata_piix.c4
-rw-r--r--drivers/scsi/libata-core.c114
-rw-r--r--drivers/scsi/libata-scsi.c16
-rw-r--r--drivers/scsi/scsi_sysfs.c31
-rw-r--r--include/linux/ata.h2
-rw-r--r--include/linux/libata.h8
-rw-r--r--include/scsi/scsi_host.h6
7 files changed, 181 insertions, 0 deletions
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 0ea27873b9ff..f79630340028 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -166,6 +166,8 @@ static struct pci_driver piix_pci_driver = {
166 .id_table = piix_pci_tbl, 166 .id_table = piix_pci_tbl,
167 .probe = piix_init_one, 167 .probe = piix_init_one,
168 .remove = ata_pci_remove_one, 168 .remove = ata_pci_remove_one,
169 .suspend = ata_pci_device_suspend,
170 .resume = ata_pci_device_resume,
169}; 171};
170 172
171static struct scsi_host_template piix_sht = { 173static struct scsi_host_template piix_sht = {
@@ -186,6 +188,8 @@ static struct scsi_host_template piix_sht = {
186 .slave_configure = ata_scsi_slave_config, 188 .slave_configure = ata_scsi_slave_config,
187 .bios_param = ata_std_bios_param, 189 .bios_param = ata_std_bios_param,
188 .ordered_flush = 1, 190 .ordered_flush = 1,
191 .resume = ata_scsi_device_resume,
192 .suspend = ata_scsi_device_suspend,
189}; 193};
190 194
191static const struct ata_port_operations piix_pata_ops = { 195static const struct ata_port_operations piix_pata_ops = {
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 */
4161static 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
4181static 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
4196static 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
4201static 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 */
4214int 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 */
4235int 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
4157int ata_port_start (struct ata_port *ap) 4247int 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
4996int 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
5004int 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);
5005EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); 5112EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
5006EXPORT_SYMBOL_GPL(ata_pci_init_one); 5113EXPORT_SYMBOL_GPL(ata_pci_init_one);
5007EXPORT_SYMBOL_GPL(ata_pci_remove_one); 5114EXPORT_SYMBOL_GPL(ata_pci_remove_one);
5115EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
5116EXPORT_SYMBOL_GPL(ata_pci_device_resume);
5008#endif /* CONFIG_PCI */ 5117#endif /* CONFIG_PCI */
5118
5119EXPORT_SYMBOL_GPL(ata_device_suspend);
5120EXPORT_SYMBOL_GPL(ata_device_resume);
5121EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
5122EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index e0439be4b573..c1ebede14a48 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -396,6 +396,22 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
396 } 396 }
397} 397}
398 398
399int ata_scsi_device_resume(struct scsi_device *sdev)
400{
401 struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
402 struct ata_device *dev = &ap->device[sdev->id];
403
404 return ata_device_resume(ap, dev);
405}
406
407int ata_scsi_device_suspend(struct scsi_device *sdev)
408{
409 struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
410 struct ata_device *dev = &ap->device[sdev->id];
411
412 return ata_device_suspend(ap, dev);
413}
414
399/** 415/**
400 * ata_to_sense_error - convert ATA error to SCSI error 416 * ata_to_sense_error - convert ATA error to SCSI error
401 * @id: ATA device number 417 * @id: ATA device number
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 15842b1f0f4a..ea7f3a433572 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -263,9 +263,40 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
263 return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; 263 return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
264} 264}
265 265
266static int scsi_bus_suspend(struct device * dev, pm_message_t state)
267{
268 struct scsi_device *sdev = to_scsi_device(dev);
269 struct scsi_host_template *sht = sdev->host->hostt;
270 int err;
271
272 err = scsi_device_quiesce(sdev);
273 if (err)
274 return err;
275
276 if (sht->suspend)
277 err = sht->suspend(sdev);
278
279 return err;
280}
281
282static int scsi_bus_resume(struct device * dev)
283{
284 struct scsi_device *sdev = to_scsi_device(dev);
285 struct scsi_host_template *sht = sdev->host->hostt;
286 int err = 0;
287
288 if (sht->resume)
289 err = sht->resume(sdev);
290
291 scsi_device_resume(sdev);
292 return err;
293}
294
266struct bus_type scsi_bus_type = { 295struct bus_type scsi_bus_type = {
267 .name = "scsi", 296 .name = "scsi",
268 .match = scsi_bus_match, 297 .match = scsi_bus_match,
298 .suspend = scsi_bus_suspend,
299 .resume = scsi_bus_resume,
269}; 300};
270 301
271int scsi_sysfs_register(void) 302int scsi_sysfs_register(void)
diff --git a/include/linux/ata.h b/include/linux/ata.h
index d2873b732bb1..3eb80c391b39 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -141,6 +141,8 @@ enum {
141 ATA_CMD_PACKET = 0xA0, 141 ATA_CMD_PACKET = 0xA0,
142 ATA_CMD_VERIFY = 0x40, 142 ATA_CMD_VERIFY = 0x40,
143 ATA_CMD_VERIFY_EXT = 0x42, 143 ATA_CMD_VERIFY_EXT = 0x42,
144 ATA_CMD_STANDBYNOW1 = 0xE0,
145 ATA_CMD_IDLEIMMEDIATE = 0xE1,
144 ATA_CMD_INIT_DEV_PARAMS = 0x91, 146 ATA_CMD_INIT_DEV_PARAMS = 0x91,
145 147
146 /* SETFEATURES stuff */ 148 /* SETFEATURES stuff */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e828e172ccbf..cdab75c209a0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -124,6 +124,8 @@ enum {
124 ATA_FLAG_DEBUGMSG = (1 << 10), 124 ATA_FLAG_DEBUGMSG = (1 << 10),
125 ATA_FLAG_NO_ATAPI = (1 << 11), /* No ATAPI support */ 125 ATA_FLAG_NO_ATAPI = (1 << 11), /* No ATAPI support */
126 126
127 ATA_FLAG_SUSPENDED = (1 << 12), /* port is suspended */
128
127 ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ 129 ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
128 ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ 130 ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
129 ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */ 131 ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */
@@ -436,6 +438,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr);
436extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, 438extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
437 unsigned int n_ports); 439 unsigned int n_ports);
438extern void ata_pci_remove_one (struct pci_dev *pdev); 440extern void ata_pci_remove_one (struct pci_dev *pdev);
441extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
442extern int ata_pci_device_resume(struct pci_dev *pdev);
439#endif /* CONFIG_PCI */ 443#endif /* CONFIG_PCI */
440extern int ata_device_add(const struct ata_probe_ent *ent); 444extern int ata_device_add(const struct ata_probe_ent *ent);
441extern void ata_host_set_remove(struct ata_host_set *host_set); 445extern void ata_host_set_remove(struct ata_host_set *host_set);
@@ -445,6 +449,10 @@ extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmn
445extern int ata_scsi_error(struct Scsi_Host *host); 449extern int ata_scsi_error(struct Scsi_Host *host);
446extern int ata_scsi_release(struct Scsi_Host *host); 450extern int ata_scsi_release(struct Scsi_Host *host);
447extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); 451extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
452extern int ata_scsi_device_resume(struct scsi_device *);
453extern int ata_scsi_device_suspend(struct scsi_device *);
454extern int ata_device_resume(struct ata_port *, struct ata_device *);
455extern int ata_device_suspend(struct ata_port *, struct ata_device *);
448extern int ata_ratelimit(void); 456extern int ata_ratelimit(void);
449 457
450/* 458/*
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 6cbb1982ed03..6297885a35e7 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -296,6 +296,12 @@ struct scsi_host_template {
296 int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); 296 int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
297 297
298 /* 298 /*
299 * suspend support
300 */
301 int (*resume)(struct scsi_device *);
302 int (*suspend)(struct scsi_device *);
303
304 /*
299 * Name of proc directory 305 * Name of proc directory
300 */ 306 */
301 char *proc_name; 307 char *proc_name;