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); |
