/[linux-patches]/genpatches-2.6/trunk/2.6.15/2300_ata-piix-suspend.patch
Gentoo

Contents of /genpatches-2.6/trunk/2.6.15/2300_ata-piix-suspend.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 249 - (show annotations) (download) (as text)
Tue Jan 10 18:15:57 2006 UTC (14 years, 10 months ago) by dsd
File MIME type: text/x-diff
File size: 8576 byte(s)
Fix crash-on-resume with ata_piix driver by implementing suspend support
1 From: Jens Axboe <axboe@suse.de>
2 Date: Fri, 6 Jan 2006 08:28:07 +0000 (+0100)
3 Subject: [PATCH] Suspend support for libata
4 X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=9b847548663ef1039dd49f0eb4463d001e596bc3
5
6 [PATCH] Suspend support for libata
7
8 This patch adds suspend patch to libata, and ata_piix in particular. For
9 most low level drivers, they should just need to add the 4 hooks to
10 work. As I can only test ata_piix, I didn't enable it for more
11 though.
12
13 Suspend support is the single most important feature on a notebook, and
14 most new notebooks have sata drives. It's quite embarrassing that we
15 _still_ do not support this. Right now, it's perfectly possible to
16 suspend the drive in mid-transfer.
17
18 Signed-off-by: Jens Axboe <axboe@suse.de>
19 Signed-off-by: Andrew Morton <akpm@osdl.org>
20 Signed-off-by: Linus Torvalds <torvalds@osdl.org>
21 ---
22
23 --- a/drivers/scsi/ata_piix.c
24 +++ b/drivers/scsi/ata_piix.c
25 @@ -166,6 +166,8 @@ static struct pci_driver piix_pci_driver
26 .id_table = piix_pci_tbl,
27 .probe = piix_init_one,
28 .remove = ata_pci_remove_one,
29 + .suspend = ata_pci_device_suspend,
30 + .resume = ata_pci_device_resume,
31 };
32
33 static struct scsi_host_template piix_sht = {
34 @@ -186,6 +188,8 @@ static struct scsi_host_template piix_sh
35 .slave_configure = ata_scsi_slave_config,
36 .bios_param = ata_std_bios_param,
37 .ordered_flush = 1,
38 + .resume = ata_scsi_device_resume,
39 + .suspend = ata_scsi_device_suspend,
40 };
41
42 static const struct ata_port_operations piix_pata_ops = {
43 --- a/drivers/scsi/libata-core.c
44 +++ b/drivers/scsi/libata-core.c
45 @@ -4154,6 +4154,96 @@ err_out:
46 * Inherited from caller.
47 */
48
49 +/*
50 + * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
51 + * without filling any other registers
52 + */
53 +static int ata_do_simple_cmd(struct ata_port *ap, struct ata_device *dev,
54 + u8 cmd)
55 +{
56 + struct ata_taskfile tf;
57 + int err;
58 +
59 + ata_tf_init(ap, &tf, dev->devno);
60 +
61 + tf.command = cmd;
62 + tf.flags |= ATA_TFLAG_DEVICE;
63 + tf.protocol = ATA_PROT_NODATA;
64 +
65 + err = ata_exec_internal(ap, dev, &tf, DMA_NONE, NULL, 0);
66 + if (err)
67 + printk(KERN_ERR "%s: ata command failed: %d\n",
68 + __FUNCTION__, err);
69 +
70 + return err;
71 +}
72 +
73 +static int ata_flush_cache(struct ata_port *ap, struct ata_device *dev)
74 +{
75 + u8 cmd;
76 +
77 + if (!ata_try_flush_cache(dev))
78 + return 0;
79 +
80 + if (ata_id_has_flush_ext(dev->id))
81 + cmd = ATA_CMD_FLUSH_EXT;
82 + else
83 + cmd = ATA_CMD_FLUSH;
84 +
85 + return ata_do_simple_cmd(ap, dev, cmd);
86 +}
87 +
88 +static int ata_standby_drive(struct ata_port *ap, struct ata_device *dev)
89 +{
90 + return ata_do_simple_cmd(ap, dev, ATA_CMD_STANDBYNOW1);
91 +}
92 +
93 +static int ata_start_drive(struct ata_port *ap, struct ata_device *dev)
94 +{
95 + return ata_do_simple_cmd(ap, dev, ATA_CMD_IDLEIMMEDIATE);
96 +}
97 +
98 +/**
99 + * ata_device_resume - wakeup a previously suspended devices
100 + *
101 + * Kick the drive back into action, by sending it an idle immediate
102 + * command and making sure its transfer mode matches between drive
103 + * and host.
104 + *
105 + */
106 +int ata_device_resume(struct ata_port *ap, struct ata_device *dev)
107 +{
108 + if (ap->flags & ATA_FLAG_SUSPENDED) {
109 + ap->flags &= ~ATA_FLAG_SUSPENDED;
110 + ata_set_mode(ap);
111 + }
112 + if (!ata_dev_present(dev))
113 + return 0;
114 + if (dev->class == ATA_DEV_ATA)
115 + ata_start_drive(ap, dev);
116 +
117 + return 0;
118 +}
119 +
120 +/**
121 + * ata_device_suspend - prepare a device for suspend
122 + *
123 + * Flush the cache on the drive, if appropriate, then issue a
124 + * standbynow command.
125 + *
126 + */
127 +int ata_device_suspend(struct ata_port *ap, struct ata_device *dev)
128 +{
129 + if (!ata_dev_present(dev))
130 + return 0;
131 + if (dev->class == ATA_DEV_ATA)
132 + ata_flush_cache(ap, dev);
133 +
134 + ata_standby_drive(ap, dev);
135 + ap->flags |= ATA_FLAG_SUSPENDED;
136 + return 0;
137 +}
138 +
139 int ata_port_start (struct ata_port *ap)
140 {
141 struct device *dev = ap->host_set->dev;
142 @@ -4902,6 +4992,23 @@ int pci_test_config_bits(struct pci_dev
143
144 return (tmp == bits->val) ? 1 : 0;
145 }
146 +
147 +int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
148 +{
149 + pci_save_state(pdev);
150 + pci_disable_device(pdev);
151 + pci_set_power_state(pdev, PCI_D3hot);
152 + return 0;
153 +}
154 +
155 +int ata_pci_device_resume(struct pci_dev *pdev)
156 +{
157 + pci_set_power_state(pdev, PCI_D0);
158 + pci_restore_state(pdev);
159 + pci_enable_device(pdev);
160 + pci_set_master(pdev);
161 + return 0;
162 +}
163 #endif /* CONFIG_PCI */
164
165
166 @@ -5005,4 +5112,11 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
167 EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
168 EXPORT_SYMBOL_GPL(ata_pci_init_one);
169 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
170 +EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
171 +EXPORT_SYMBOL_GPL(ata_pci_device_resume);
172 #endif /* CONFIG_PCI */
173 +
174 +EXPORT_SYMBOL_GPL(ata_device_suspend);
175 +EXPORT_SYMBOL_GPL(ata_device_resume);
176 +EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
177 +EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
178 --- a/drivers/scsi/libata-scsi.c
179 +++ b/drivers/scsi/libata-scsi.c
180 @@ -396,6 +396,22 @@ void ata_dump_status(unsigned id, struct
181 }
182 }
183
184 +int ata_scsi_device_resume(struct scsi_device *sdev)
185 +{
186 + struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
187 + struct ata_device *dev = &ap->device[sdev->id];
188 +
189 + return ata_device_resume(ap, dev);
190 +}
191 +
192 +int ata_scsi_device_suspend(struct scsi_device *sdev)
193 +{
194 + struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0];
195 + struct ata_device *dev = &ap->device[sdev->id];
196 +
197 + return ata_device_suspend(ap, dev);
198 +}
199 +
200 /**
201 * ata_to_sense_error - convert ATA error to SCSI error
202 * @id: ATA device number
203 --- a/drivers/scsi/scsi_sysfs.c
204 +++ b/drivers/scsi/scsi_sysfs.c
205 @@ -263,9 +263,40 @@ static int scsi_bus_match(struct device
206 return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
207 }
208
209 +static int scsi_bus_suspend(struct device * dev, pm_message_t state)
210 +{
211 + struct scsi_device *sdev = to_scsi_device(dev);
212 + struct scsi_host_template *sht = sdev->host->hostt;
213 + int err;
214 +
215 + err = scsi_device_quiesce(sdev);
216 + if (err)
217 + return err;
218 +
219 + if (sht->suspend)
220 + err = sht->suspend(sdev);
221 +
222 + return err;
223 +}
224 +
225 +static int scsi_bus_resume(struct device * dev)
226 +{
227 + struct scsi_device *sdev = to_scsi_device(dev);
228 + struct scsi_host_template *sht = sdev->host->hostt;
229 + int err = 0;
230 +
231 + if (sht->resume)
232 + err = sht->resume(sdev);
233 +
234 + scsi_device_resume(sdev);
235 + return err;
236 +}
237 +
238 struct bus_type scsi_bus_type = {
239 .name = "scsi",
240 .match = scsi_bus_match,
241 + .suspend = scsi_bus_suspend,
242 + .resume = scsi_bus_resume,
243 };
244
245 int scsi_sysfs_register(void)
246 --- a/include/linux/ata.h
247 +++ b/include/linux/ata.h
248 @@ -141,6 +141,8 @@ enum {
249 ATA_CMD_PACKET = 0xA0,
250 ATA_CMD_VERIFY = 0x40,
251 ATA_CMD_VERIFY_EXT = 0x42,
252 + ATA_CMD_STANDBYNOW1 = 0xE0,
253 + ATA_CMD_IDLEIMMEDIATE = 0xE1,
254 ATA_CMD_INIT_DEV_PARAMS = 0x91,
255
256 /* SETFEATURES stuff */
257 --- a/include/linux/libata.h
258 +++ b/include/linux/libata.h
259 @@ -124,6 +124,8 @@ enum {
260 ATA_FLAG_DEBUGMSG = (1 << 10),
261 ATA_FLAG_NO_ATAPI = (1 << 11), /* No ATAPI support */
262
263 + ATA_FLAG_SUSPENDED = (1 << 12), /* port is suspended */
264 +
265 ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */
266 ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */
267 ATA_QCFLAG_SINGLE = (1 << 4), /* no s/g, just a single buffer */
268 @@ -436,6 +438,8 @@ extern void ata_std_ports(struct ata_iop
269 extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
270 unsigned int n_ports);
271 extern void ata_pci_remove_one (struct pci_dev *pdev);
272 +extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
273 +extern int ata_pci_device_resume(struct pci_dev *pdev);
274 #endif /* CONFIG_PCI */
275 extern int ata_device_add(const struct ata_probe_ent *ent);
276 extern void ata_host_set_remove(struct ata_host_set *host_set);
277 @@ -445,6 +449,10 @@ extern int ata_scsi_queuecmd(struct scsi
278 extern int ata_scsi_error(struct Scsi_Host *host);
279 extern int ata_scsi_release(struct Scsi_Host *host);
280 extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
281 +extern int ata_scsi_device_resume(struct scsi_device *);
282 +extern int ata_scsi_device_suspend(struct scsi_device *);
283 +extern int ata_device_resume(struct ata_port *, struct ata_device *);
284 +extern int ata_device_suspend(struct ata_port *, struct ata_device *);
285 extern int ata_ratelimit(void);
286
287 /*
288 --- a/include/scsi/scsi_host.h
289 +++ b/include/scsi/scsi_host.h
290 @@ -296,6 +296,12 @@ struct scsi_host_template {
291 int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
292
293 /*
294 + * suspend support
295 + */
296 + int (*resume)(struct scsi_device *);
297 + int (*suspend)(struct scsi_device *);
298 +
299 + /*
300 * Name of proc directory
301 */
302 char *proc_name;

  ViewVC Help
Powered by ViewVC 1.1.20