diff options
author | Tejun Heo <htejun@gmail.com> | 2007-05-14 14:28:16 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-07-09 12:17:31 -0400 |
commit | 4700c4bc9262a9e78f7197c4c41cc2be085d5276 (patch) | |
tree | 2156bedcbcfdee5d22dfb0a43f71bd4813933b7e | |
parent | fafbae87db88a73b166d3bc3294d209207f27056 (diff) |
libata-acpi: clean up ata_acpi_exec_tfs()
This patch cleans up ata_acpi_exec_tfs() and its friends.
* Rename taskfile_array to ata_acpi_gtf and make it __packed as it's
used as argument to ACPI method, and use pointer to ata_acpi_gtf and
number of taskfiles to represent _GTF taskfiles instead of a pointer
casted into unsigned long and byte count. This makes argument
re-checking in do_drive_set_taskfiles() unnecessary.
* Pointer in void * not in unsigned long.
* Clean up do_drive_get_GTF() error handling and make
do_drive_get_GTF() return number of taskfiles on success, 0 if _GTF
doesn't exist or doesn't contain valid ata. -errno on other errors.
* Remove superflous check for acpi->buffer.pointer.
* Update taskfile_load_raw() such that printed messages look similar
to the messages printed by ata_eh_report().
* s/do_drive_get_GTF/ata_dev_get_GTF/
s/do_drive_set_taskfiles/ata_dev_set_taskfiles/
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/libata-acpi.c | 226 |
1 files changed, 111 insertions, 115 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index eda4263b4017..4d36d254730b 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -28,9 +28,9 @@ | |||
28 | #define SATA_ADR(root,pmp) (((root) << 16) | (pmp)) | 28 | #define SATA_ADR(root,pmp) (((root) << 16) | (pmp)) |
29 | 29 | ||
30 | #define REGS_PER_GTF 7 | 30 | #define REGS_PER_GTF 7 |
31 | struct taskfile_array { | 31 | struct ata_acpi_gtf { |
32 | u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ | 32 | u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ |
33 | }; | 33 | } __packed; |
34 | 34 | ||
35 | /* | 35 | /* |
36 | * Helper - belongs in the PCI layer somewhere eventually | 36 | * Helper - belongs in the PCI layer somewhere eventually |
@@ -101,10 +101,10 @@ void ata_acpi_associate(struct ata_host *host) | |||
101 | } | 101 | } |
102 | 102 | ||
103 | /** | 103 | /** |
104 | * do_drive_get_GTF - get the drive bootup default taskfile settings | 104 | * ata_dev_get_GTF - get the drive bootup default taskfile settings |
105 | * @dev: target ATA device | 105 | * @dev: target ATA device |
106 | * @gtf_length: number of bytes of _GTF data returned at @gtf_address | 106 | * @gtf: output parameter for buffer containing _GTF taskfile arrays |
107 | * @gtf_address: buffer containing _GTF taskfile arrays | 107 | * @ptr_to_free: pointer which should be freed |
108 | * | 108 | * |
109 | * This applies to both PATA and SATA drives. | 109 | * This applies to both PATA and SATA drives. |
110 | * | 110 | * |
@@ -114,24 +114,28 @@ void ata_acpi_associate(struct ata_host *host) | |||
114 | * The <variable number> is not known in advance, so have ACPI-CA | 114 | * The <variable number> is not known in advance, so have ACPI-CA |
115 | * allocate the buffer as needed and return it, then free it later. | 115 | * allocate the buffer as needed and return it, then free it later. |
116 | * | 116 | * |
117 | * The returned @gtf_length and @gtf_address are only valid if the | 117 | * LOCKING: |
118 | * function return value is 0. | 118 | * EH context. |
119 | * | ||
120 | * RETURNS: | ||
121 | * Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't | ||
122 | * contain valid data. -errno on other errors. | ||
119 | */ | 123 | */ |
120 | static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, | 124 | static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, |
121 | unsigned long *gtf_address, unsigned long *obj_loc) | 125 | void **ptr_to_free) |
122 | { | 126 | { |
123 | struct ata_port *ap = dev->ap; | 127 | struct ata_port *ap = dev->ap; |
124 | acpi_status status; | 128 | acpi_status status; |
125 | struct acpi_buffer output; | 129 | struct acpi_buffer output; |
126 | union acpi_object *out_obj; | 130 | union acpi_object *out_obj; |
127 | int err = -ENODEV; | 131 | int rc = 0; |
128 | 132 | ||
129 | *gtf_length = 0; | 133 | /* set up output buffer */ |
130 | *gtf_address = 0UL; | 134 | output.length = ACPI_ALLOCATE_BUFFER; |
131 | *obj_loc = 0UL; | 135 | output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ |
132 | 136 | ||
133 | if (!dev->acpi_handle) | 137 | if (!dev->acpi_handle) |
134 | return 0; | 138 | goto out_free; |
135 | 139 | ||
136 | if (ata_msg_probe(ap)) | 140 | if (ata_msg_probe(ap)) |
137 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", | 141 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", |
@@ -143,23 +147,20 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, | |||
143 | "ata_dev_present: %d, PORT_DISABLED: %lu\n", | 147 | "ata_dev_present: %d, PORT_DISABLED: %lu\n", |
144 | __FUNCTION__, ata_dev_enabled(dev), | 148 | __FUNCTION__, ata_dev_enabled(dev), |
145 | ap->flags & ATA_FLAG_DISABLED); | 149 | ap->flags & ATA_FLAG_DISABLED); |
146 | goto out; | 150 | goto out_free; |
147 | } | 151 | } |
148 | 152 | ||
149 | /* Setting up output buffer */ | ||
150 | output.length = ACPI_ALLOCATE_BUFFER; | ||
151 | output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ | ||
152 | |||
153 | /* _GTF has no input parameters */ | 153 | /* _GTF has no input parameters */ |
154 | err = -EIO; | 154 | status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); |
155 | status = acpi_evaluate_object(dev->acpi_handle, "_GTF", | 155 | |
156 | NULL, &output); | ||
157 | if (ACPI_FAILURE(status)) { | 156 | if (ACPI_FAILURE(status)) { |
158 | if (ata_msg_probe(ap)) | 157 | if (status != AE_NOT_FOUND) { |
159 | ata_dev_printk(dev, KERN_DEBUG, | 158 | ata_dev_printk(dev, KERN_WARNING, |
160 | "%s: Run _GTF error: status = 0x%x\n", | 159 | "_GTF evaluation failed (AE 0x%x)\n", |
161 | __FUNCTION__, status); | 160 | status); |
162 | goto out; | 161 | rc = -EIO; |
162 | } | ||
163 | goto out_free; | ||
163 | } | 164 | } |
164 | 165 | ||
165 | if (!output.length || !output.pointer) { | 166 | if (!output.length || !output.pointer) { |
@@ -169,43 +170,43 @@ static int do_drive_get_GTF(struct ata_device *dev, unsigned int *gtf_length, | |||
169 | __FUNCTION__, | 170 | __FUNCTION__, |
170 | (unsigned long long)output.length, | 171 | (unsigned long long)output.length, |
171 | output.pointer); | 172 | output.pointer); |
172 | kfree(output.pointer); | 173 | goto out_free; |
173 | goto out; | ||
174 | } | 174 | } |
175 | 175 | ||
176 | out_obj = output.pointer; | 176 | out_obj = output.pointer; |
177 | if (out_obj->type != ACPI_TYPE_BUFFER) { | 177 | if (out_obj->type != ACPI_TYPE_BUFFER) { |
178 | kfree(output.pointer); | ||
179 | if (ata_msg_probe(ap)) | 178 | if (ata_msg_probe(ap)) |
180 | ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " | 179 | ata_dev_printk(dev, KERN_DEBUG, "%s: Run _GTF: " |
181 | "error: expected object type of " | 180 | "error: expected object type of " |
182 | " ACPI_TYPE_BUFFER, got 0x%x\n", | 181 | " ACPI_TYPE_BUFFER, got 0x%x\n", |
183 | __FUNCTION__, out_obj->type); | 182 | __FUNCTION__, out_obj->type); |
184 | err = -ENOENT; | 183 | rc = -EINVAL; |
185 | goto out; | 184 | goto out_free; |
186 | } | 185 | } |
187 | 186 | ||
188 | if (!out_obj->buffer.length || !out_obj->buffer.pointer || | 187 | if (out_obj->buffer.length % REGS_PER_GTF) { |
189 | out_obj->buffer.length % REGS_PER_GTF) { | ||
190 | if (ata_msg_drv(ap)) | 188 | if (ata_msg_drv(ap)) |
191 | ata_dev_printk(dev, KERN_ERR, | 189 | ata_dev_printk(dev, KERN_ERR, |
192 | "%s: unexpected GTF length (%d) or addr (0x%p)\n", | 190 | "%s: unexpected GTF length (%d) or addr (0x%p)\n", |
193 | __FUNCTION__, out_obj->buffer.length, | 191 | __FUNCTION__, out_obj->buffer.length, |
194 | out_obj->buffer.pointer); | 192 | out_obj->buffer.pointer); |
195 | err = -ENOENT; | 193 | rc = -EINVAL; |
196 | goto out; | 194 | goto out_free; |
197 | } | 195 | } |
198 | 196 | ||
199 | *gtf_length = out_obj->buffer.length; | 197 | *ptr_to_free = out_obj; |
200 | *gtf_address = (unsigned long)out_obj->buffer.pointer; | 198 | *gtf = (void *)out_obj->buffer.pointer; |
201 | *obj_loc = (unsigned long)out_obj; | 199 | rc = out_obj->buffer.length / REGS_PER_GTF; |
200 | |||
202 | if (ata_msg_probe(ap)) | 201 | if (ata_msg_probe(ap)) |
203 | ata_dev_printk(dev, KERN_DEBUG, "%s: returning " | 202 | ata_dev_printk(dev, KERN_DEBUG, "%s: returning " |
204 | "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", | 203 | "gtf=%p, gtf_count=%d, ptr_to_free=%p\n", |
205 | __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); | 204 | __FUNCTION__, *gtf, rc, *ptr_to_free); |
206 | err = 0; | 205 | return rc; |
207 | out: | 206 | |
208 | return err; | 207 | out_free: |
208 | kfree(output.pointer); | ||
209 | return rc; | ||
209 | } | 210 | } |
210 | 211 | ||
211 | /** | 212 | /** |
@@ -224,68 +225,78 @@ out: | |||
224 | * function also waits for idle after writing control and before | 225 | * function also waits for idle after writing control and before |
225 | * writing the remaining registers. | 226 | * writing the remaining registers. |
226 | * | 227 | * |
227 | * LOCKING: TBD: | 228 | * LOCKING: |
228 | * Inherited from caller. | 229 | * EH context. |
230 | * | ||
231 | * RETURNS: | ||
232 | * 0 on success, -errno on failure. | ||
229 | */ | 233 | */ |
230 | static void taskfile_load_raw(struct ata_device *dev, | 234 | static int taskfile_load_raw(struct ata_device *dev, |
231 | const struct taskfile_array *gtf) | 235 | const struct ata_acpi_gtf *gtf) |
232 | { | 236 | { |
233 | struct ata_port *ap = dev->ap; | 237 | struct ata_port *ap = dev->ap; |
234 | struct ata_taskfile tf; | 238 | struct ata_taskfile tf, rtf; |
235 | unsigned int err; | 239 | unsigned int err_mask; |
236 | 240 | ||
237 | if (ata_msg_probe(ap)) | 241 | if ((gtf->tf[0] == 0) && (gtf->tf[1] == 0) && (gtf->tf[2] == 0) |
238 | ata_dev_printk(dev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " | 242 | && (gtf->tf[3] == 0) && (gtf->tf[4] == 0) && (gtf->tf[5] == 0) |
239 | "%02x %02x %02x %02x %02x %02x %02x\n", | 243 | && (gtf->tf[6] == 0)) |
240 | __FUNCTION__, | 244 | return 0; |
241 | gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], | ||
242 | gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); | ||
243 | |||
244 | if ((gtf->tfa[0] == 0) && (gtf->tfa[1] == 0) && (gtf->tfa[2] == 0) | ||
245 | && (gtf->tfa[3] == 0) && (gtf->tfa[4] == 0) && (gtf->tfa[5] == 0) | ||
246 | && (gtf->tfa[6] == 0)) | ||
247 | return; | ||
248 | 245 | ||
249 | ata_tf_init(dev, &tf); | 246 | ata_tf_init(dev, &tf); |
250 | 247 | ||
251 | /* convert gtf to tf */ | 248 | /* convert gtf to tf */ |
252 | tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ | 249 | tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ |
253 | tf.protocol = ATA_PROT_NODATA; | 250 | tf.protocol = ATA_PROT_NODATA; |
254 | tf.feature = gtf->tfa[0]; /* 0x1f1 */ | 251 | tf.feature = gtf->tf[0]; /* 0x1f1 */ |
255 | tf.nsect = gtf->tfa[1]; /* 0x1f2 */ | 252 | tf.nsect = gtf->tf[1]; /* 0x1f2 */ |
256 | tf.lbal = gtf->tfa[2]; /* 0x1f3 */ | 253 | tf.lbal = gtf->tf[2]; /* 0x1f3 */ |
257 | tf.lbam = gtf->tfa[3]; /* 0x1f4 */ | 254 | tf.lbam = gtf->tf[3]; /* 0x1f4 */ |
258 | tf.lbah = gtf->tfa[4]; /* 0x1f5 */ | 255 | tf.lbah = gtf->tf[4]; /* 0x1f5 */ |
259 | tf.device = gtf->tfa[5]; /* 0x1f6 */ | 256 | tf.device = gtf->tf[5]; /* 0x1f6 */ |
260 | tf.command = gtf->tfa[6]; /* 0x1f7 */ | 257 | tf.command = gtf->tf[6]; /* 0x1f7 */ |
261 | 258 | ||
262 | err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0); | 259 | if (ata_msg_probe(ap)) |
263 | if (err && ata_msg_probe(ap)) | 260 | ata_dev_printk(dev, KERN_DEBUG, "executing ACPI cmd " |
261 | "%02x/%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
262 | tf.command, tf.feature, tf.nsect, | ||
263 | tf.lbal, tf.lbam, tf.lbah, tf.device); | ||
264 | |||
265 | rtf = tf; | ||
266 | err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0); | ||
267 | if (err_mask) { | ||
264 | ata_dev_printk(dev, KERN_ERR, | 268 | ata_dev_printk(dev, KERN_ERR, |
265 | "%s: ata_exec_internal failed: %u\n", | 269 | "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " |
266 | __FUNCTION__, err); | 270 | "(Emask=0x%x Stat=0x%02x Err=0x%02x)\n", |
271 | tf.command, tf.feature, tf.nsect, tf.lbal, tf.lbam, | ||
272 | tf.lbah, tf.device, err_mask, rtf.command, rtf.feature); | ||
273 | return -EIO; | ||
274 | } | ||
275 | |||
276 | return 0; | ||
267 | } | 277 | } |
268 | 278 | ||
269 | /** | 279 | /** |
270 | * do_drive_set_taskfiles - write the drive taskfile settings from _GTF | 280 | * ata_dev_set_taskfiles - write the drive taskfile settings from _GTF |
271 | * @dev: target ATA device | 281 | * @dev: target ATA device |
272 | * @gtf_length: total number of bytes of _GTF taskfiles | 282 | * @gtf: pointer to array of _GTF taskfiles to execute |
273 | * @gtf_address: location of _GTF taskfile arrays | 283 | * @gtf_count: number of taskfiles |
274 | * | 284 | * |
275 | * This applies to both PATA and SATA drives. | 285 | * This applies to both PATA and SATA drives. |
276 | * | 286 | * |
277 | * Write {gtf_address, length gtf_length} in groups of | 287 | * Execute taskfiles in @gtf. |
278 | * REGS_PER_GTF bytes. | 288 | * |
289 | * LOCKING: | ||
290 | * EH context. | ||
291 | * | ||
292 | * RETURNS: | ||
293 | * 0 on success, -errno on failure. | ||
279 | */ | 294 | */ |
280 | static int do_drive_set_taskfiles(struct ata_device *dev, | 295 | static int ata_dev_set_taskfiles(struct ata_device *dev, |
281 | unsigned int gtf_length, | 296 | struct ata_acpi_gtf *gtf, int gtf_count) |
282 | unsigned long gtf_address) | ||
283 | { | 297 | { |
284 | struct ata_port *ap = dev->ap; | 298 | struct ata_port *ap = dev->ap; |
285 | int err = -ENODEV; | ||
286 | int gtf_count = gtf_length / REGS_PER_GTF; | ||
287 | int ix; | 299 | int ix; |
288 | struct taskfile_array *gtf; | ||
289 | 300 | ||
290 | if (ata_msg_probe(ap)) | 301 | if (ata_msg_probe(ap)) |
291 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", | 302 | ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n", |
@@ -295,29 +306,13 @@ static int do_drive_set_taskfiles(struct ata_device *dev, | |||
295 | return 0; | 306 | return 0; |
296 | 307 | ||
297 | if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED)) | 308 | if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED)) |
298 | goto out; | 309 | return -ENODEV; |
299 | if (!gtf_count) /* shouldn't be here */ | ||
300 | goto out; | ||
301 | |||
302 | if (gtf_length % REGS_PER_GTF) { | ||
303 | if (ata_msg_drv(ap)) | ||
304 | ata_dev_printk(dev, KERN_ERR, | ||
305 | "%s: unexpected GTF length (%d)\n", | ||
306 | __FUNCTION__, gtf_length); | ||
307 | goto out; | ||
308 | } | ||
309 | 310 | ||
310 | for (ix = 0; ix < gtf_count; ix++) { | 311 | /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ |
311 | gtf = (struct taskfile_array *) | 312 | for (ix = 0; ix < gtf_count; ix++) |
312 | (gtf_address + ix * REGS_PER_GTF); | 313 | taskfile_load_raw(dev, gtf++); |
313 | 314 | ||
314 | /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ | 315 | return 0; |
315 | taskfile_load_raw(dev, gtf); | ||
316 | } | ||
317 | |||
318 | err = 0; | ||
319 | out: | ||
320 | return err; | ||
321 | } | 316 | } |
322 | 317 | ||
323 | /** | 318 | /** |
@@ -328,11 +323,7 @@ out: | |||
328 | */ | 323 | */ |
329 | int ata_acpi_exec_tfs(struct ata_port *ap) | 324 | int ata_acpi_exec_tfs(struct ata_port *ap) |
330 | { | 325 | { |
331 | int ix; | 326 | int ix, ret = 0; |
332 | int ret = 0; | ||
333 | unsigned int gtf_length; | ||
334 | unsigned long gtf_address; | ||
335 | unsigned long obj_loc; | ||
336 | 327 | ||
337 | /* | 328 | /* |
338 | * TBD - implement PATA support. For now, | 329 | * TBD - implement PATA support. For now, |
@@ -344,12 +335,16 @@ int ata_acpi_exec_tfs(struct ata_port *ap) | |||
344 | 335 | ||
345 | for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { | 336 | for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { |
346 | struct ata_device *dev = &ap->device[ix]; | 337 | struct ata_device *dev = &ap->device[ix]; |
338 | struct ata_acpi_gtf *gtf = NULL; | ||
339 | int gtf_count; | ||
340 | void *ptr_to_free = NULL; | ||
347 | 341 | ||
348 | if (!ata_dev_enabled(dev)) | 342 | if (!ata_dev_enabled(dev)) |
349 | continue; | 343 | continue; |
350 | 344 | ||
351 | ret = do_drive_get_GTF(dev, >f_length, >f_address, | 345 | ret = ata_dev_get_GTF(dev, >f, &ptr_to_free); |
352 | &obj_loc); | 346 | if (ret == 0) |
347 | continue; | ||
353 | if (ret < 0) { | 348 | if (ret < 0) { |
354 | if (ata_msg_probe(ap)) | 349 | if (ata_msg_probe(ap)) |
355 | ata_port_printk(ap, KERN_DEBUG, | 350 | ata_port_printk(ap, KERN_DEBUG, |
@@ -357,9 +352,10 @@ int ata_acpi_exec_tfs(struct ata_port *ap) | |||
357 | __FUNCTION__, ret); | 352 | __FUNCTION__, ret); |
358 | break; | 353 | break; |
359 | } | 354 | } |
355 | gtf_count = ret; | ||
360 | 356 | ||
361 | ret = do_drive_set_taskfiles(dev, gtf_length, gtf_address); | 357 | ret = ata_dev_set_taskfiles(dev, gtf, gtf_count); |
362 | kfree((void *)obj_loc); | 358 | kfree(ptr_to_free); |
363 | if (ret < 0) { | 359 | if (ret < 0) { |
364 | if (ata_msg_probe(ap)) | 360 | if (ata_msg_probe(ap)) |
365 | ata_port_printk(ap, KERN_DEBUG, | 361 | ata_port_printk(ap, KERN_DEBUG, |