diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-06-23 07:29:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-08-07 13:42:59 -0400 |
commit | fa56d4cb4022c8b313c3b99236e1b87effc3655b (patch) | |
tree | b51b1e66ac75b1412f57f7e41e3aff4bc8f0f0f7 | |
parent | 2d5abcedeb41f4af9582c60cef70749c3ab90a3b (diff) |
ide: allow ide_dev_read_id() to be called from the IRQ context
* Un-static __ide_wait_stat().
* Allow ide_dev_read_id() helper to be called from the IRQ context by
adding irq_ctx flag and using mdelay()/__ide_wait_stat() when needed.
* Switch ide_driveid_update() to set irq_ctx flag.
This change is needed for the consecutive patch which fixes races in
handling of user-space SET XFER commands but for improved bisectability
and clarity it is better to do it in a separate patch.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/ide/ide-iops.c | 6 | ||||
-rw-r--r-- | drivers/ide/ide-probe.c | 31 | ||||
-rw-r--r-- | include/linux/ide.h | 3 |
3 files changed, 26 insertions, 14 deletions
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 2892b242bbe1..b99873845d21 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c | |||
@@ -102,8 +102,8 @@ EXPORT_SYMBOL(ide_fixstring); | |||
102 | * setting a timer to wake up at half second intervals thereafter, | 102 | * setting a timer to wake up at half second intervals thereafter, |
103 | * until timeout is achieved, before timing out. | 103 | * until timeout is achieved, before timing out. |
104 | */ | 104 | */ |
105 | static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, | 105 | int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, |
106 | unsigned long timeout, u8 *rstat) | 106 | unsigned long timeout, u8 *rstat) |
107 | { | 107 | { |
108 | ide_hwif_t *hwif = drive->hwif; | 108 | ide_hwif_t *hwif = drive->hwif; |
109 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | 109 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
@@ -316,7 +316,7 @@ int ide_driveid_update(ide_drive_t *drive) | |||
316 | return 0; | 316 | return 0; |
317 | 317 | ||
318 | SELECT_MASK(drive, 1); | 318 | SELECT_MASK(drive, 1); |
319 | rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id); | 319 | rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1); |
320 | SELECT_MASK(drive, 0); | 320 | SELECT_MASK(drive, 0); |
321 | 321 | ||
322 | if (rc) | 322 | if (rc) |
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 1bb106f6221a..8de442cbee94 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c | |||
@@ -238,6 +238,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id) | |||
238 | * @drive: drive to identify | 238 | * @drive: drive to identify |
239 | * @cmd: command to use | 239 | * @cmd: command to use |
240 | * @id: buffer for IDENTIFY data | 240 | * @id: buffer for IDENTIFY data |
241 | * @irq_ctx: flag set when called from the IRQ context | ||
241 | * | 242 | * |
242 | * Sends an ATA(PI) IDENTIFY request to a drive and waits for a response. | 243 | * Sends an ATA(PI) IDENTIFY request to a drive and waits for a response. |
243 | * | 244 | * |
@@ -246,7 +247,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id) | |||
246 | * 2 device aborted the command (refused to identify itself) | 247 | * 2 device aborted the command (refused to identify itself) |
247 | */ | 248 | */ |
248 | 249 | ||
249 | int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id) | 250 | int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx) |
250 | { | 251 | { |
251 | ide_hwif_t *hwif = drive->hwif; | 252 | ide_hwif_t *hwif = drive->hwif; |
252 | struct ide_io_ports *io_ports = &hwif->io_ports; | 253 | struct ide_io_ports *io_ports = &hwif->io_ports; |
@@ -263,7 +264,10 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id) | |||
263 | tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); | 264 | tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); |
264 | 265 | ||
265 | /* take a deep breath */ | 266 | /* take a deep breath */ |
266 | msleep(50); | 267 | if (irq_ctx) |
268 | mdelay(50); | ||
269 | else | ||
270 | msleep(50); | ||
267 | 271 | ||
268 | if (io_ports->ctl_addr && | 272 | if (io_ports->ctl_addr && |
269 | (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) { | 273 | (hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0) { |
@@ -295,12 +299,19 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id) | |||
295 | 299 | ||
296 | timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; | 300 | timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2; |
297 | 301 | ||
298 | if (ide_busy_sleep(drive, timeout, use_altstatus)) | ||
299 | return 1; | ||
300 | |||
301 | /* wait for IRQ and ATA_DRQ */ | 302 | /* wait for IRQ and ATA_DRQ */ |
302 | msleep(50); | 303 | if (irq_ctx) { |
303 | s = tp_ops->read_status(hwif); | 304 | rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s); |
305 | if (rc) | ||
306 | return 1; | ||
307 | } else { | ||
308 | rc = ide_busy_sleep(drive, timeout, use_altstatus); | ||
309 | if (rc) | ||
310 | return 1; | ||
311 | |||
312 | msleep(50); | ||
313 | s = tp_ops->read_status(hwif); | ||
314 | } | ||
304 | 315 | ||
305 | if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) { | 316 | if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) { |
306 | /* drive returned ID */ | 317 | /* drive returned ID */ |
@@ -406,10 +417,10 @@ static int do_probe (ide_drive_t *drive, u8 cmd) | |||
406 | 417 | ||
407 | if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) || | 418 | if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) || |
408 | present || cmd == ATA_CMD_ID_ATAPI) { | 419 | present || cmd == ATA_CMD_ID_ATAPI) { |
409 | rc = ide_dev_read_id(drive, cmd, id); | 420 | rc = ide_dev_read_id(drive, cmd, id, 0); |
410 | if (rc) | 421 | if (rc) |
411 | /* failed: try again */ | 422 | /* failed: try again */ |
412 | rc = ide_dev_read_id(drive, cmd, id); | 423 | rc = ide_dev_read_id(drive, cmd, id, 0); |
413 | 424 | ||
414 | stat = tp_ops->read_status(hwif); | 425 | stat = tp_ops->read_status(hwif); |
415 | 426 | ||
@@ -424,7 +435,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) | |||
424 | msleep(50); | 435 | msleep(50); |
425 | tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); | 436 | tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); |
426 | (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0); | 437 | (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0); |
427 | rc = ide_dev_read_id(drive, cmd, id); | 438 | rc = ide_dev_read_id(drive, cmd, id, 0); |
428 | } | 439 | } |
429 | 440 | ||
430 | /* ensure drive IRQ is clear */ | 441 | /* ensure drive IRQ is clear */ |
diff --git a/include/linux/ide.h b/include/linux/ide.h index edc93a6d931d..cb6cd0459a5e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -1081,6 +1081,7 @@ extern void ide_fixstring(u8 *, const int, const int); | |||
1081 | 1081 | ||
1082 | int ide_busy_sleep(ide_drive_t *, unsigned long, int); | 1082 | int ide_busy_sleep(ide_drive_t *, unsigned long, int); |
1083 | 1083 | ||
1084 | int __ide_wait_stat(ide_drive_t *, u8, u8, unsigned long, u8 *); | ||
1084 | int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long); | 1085 | int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long); |
1085 | 1086 | ||
1086 | ide_startstop_t ide_do_park_unpark(ide_drive_t *, struct request *); | 1087 | ide_startstop_t ide_do_park_unpark(ide_drive_t *, struct request *); |
@@ -1169,7 +1170,7 @@ int ide_no_data_taskfile(ide_drive_t *, struct ide_cmd *); | |||
1169 | 1170 | ||
1170 | int ide_taskfile_ioctl(ide_drive_t *, unsigned long); | 1171 | int ide_taskfile_ioctl(ide_drive_t *, unsigned long); |
1171 | 1172 | ||
1172 | int ide_dev_read_id(ide_drive_t *, u8, u16 *); | 1173 | int ide_dev_read_id(ide_drive_t *, u8, u16 *, int); |
1173 | 1174 | ||
1174 | extern int ide_driveid_update(ide_drive_t *); | 1175 | extern int ide_driveid_update(ide_drive_t *); |
1175 | extern int ide_config_drive_speed(ide_drive_t *, u8); | 1176 | extern int ide_config_drive_speed(ide_drive_t *, u8); |