ide: allow ide_dev_read_id() to be called from the IRQ context
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Tue, 23 Jun 2009 11:29:11 +0000 (11:29 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Aug 2009 17:42:59 +0000 (10:42 -0700)
* 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>
drivers/ide/ide-iops.c
drivers/ide/ide-probe.c
include/linux/ide.h

index 2892b242bbe1c84feed1a343bdbb6494135f9e9a..b99873845d21a92c8fe4e8a7b36ae9aff18895e7 100644 (file)
@@ -102,8 +102,8 @@ EXPORT_SYMBOL(ide_fixstring);
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
-                          unsigned long timeout, u8 *rstat)
+int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad,
+                   unsigned long timeout, u8 *rstat)
 {
        ide_hwif_t *hwif = drive->hwif;
        const struct ide_tp_ops *tp_ops = hwif->tp_ops;
@@ -316,7 +316,7 @@ int ide_driveid_update(ide_drive_t *drive)
                return 0;
 
        SELECT_MASK(drive, 1);
-       rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id);
+       rc = ide_dev_read_id(drive, ATA_CMD_ID_ATA, id, 1);
        SELECT_MASK(drive, 0);
 
        if (rc)
index 1bb106f6221a5aad84aa6385158b23d53b9eaa69..8de442cbee948ca7a6fa646654c08c55650d66a4 100644 (file)
@@ -238,6 +238,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
  *     @drive: drive to identify
  *     @cmd: command to use
  *     @id: buffer for IDENTIFY data
+ *     @irq_ctx: flag set when called from the IRQ context
  *
  *     Sends an ATA(PI) IDENTIFY request to a drive and waits for a response.
  *
@@ -246,7 +247,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd, u16 *id)
  *                     2  device aborted the command (refused to identify itself)
  */
 
-int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id)
+int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id, int irq_ctx)
 {
        ide_hwif_t *hwif = drive->hwif;
        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)
                tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS);
 
        /* take a deep breath */
-       msleep(50);
+       if (irq_ctx)
+               mdelay(50);
+       else
+               msleep(50);
 
        if (io_ports->ctl_addr &&
            (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)
 
        timeout = ((cmd == ATA_CMD_ID_ATA) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
 
-       if (ide_busy_sleep(drive, timeout, use_altstatus))
-               return 1;
-
        /* wait for IRQ and ATA_DRQ */
-       msleep(50);
-       s = tp_ops->read_status(hwif);
+       if (irq_ctx) {
+               rc = __ide_wait_stat(drive, ATA_DRQ, BAD_R_STAT, timeout, &s);
+               if (rc)
+                       return 1;
+       } else {
+               rc = ide_busy_sleep(drive, timeout, use_altstatus);
+               if (rc)
+                       return 1;
+
+               msleep(50);
+               s = tp_ops->read_status(hwif);
+       }
 
        if (OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
                /* drive returned ID */
@@ -406,10 +417,10 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
 
        if (OK_STAT(stat, ATA_DRDY, ATA_BUSY) ||
            present || cmd == ATA_CMD_ID_ATAPI) {
-               rc = ide_dev_read_id(drive, cmd, id);
+               rc = ide_dev_read_id(drive, cmd, id, 0);
                if (rc)
                        /* failed: try again */
-                       rc = ide_dev_read_id(drive, cmd, id);
+                       rc = ide_dev_read_id(drive, cmd, id, 0);
 
                stat = tp_ops->read_status(hwif);
 
@@ -424,7 +435,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd)
                        msleep(50);
                        tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
                        (void)ide_busy_sleep(drive, WAIT_WORSTCASE, 0);
-                       rc = ide_dev_read_id(drive, cmd, id);
+                       rc = ide_dev_read_id(drive, cmd, id, 0);
                }
 
                /* ensure drive IRQ is clear */
index edc93a6d931db45fecc9ba3064aecb0619ea6115..cb6cd0459a5ee13bbe8f1ad915b528f45d0b74e8 100644 (file)
@@ -1081,6 +1081,7 @@ extern void ide_fixstring(u8 *, const int, const int);
 
 int ide_busy_sleep(ide_drive_t *, unsigned long, int);
 
+int __ide_wait_stat(ide_drive_t *, u8, u8, unsigned long, u8 *);
 int ide_wait_stat(ide_startstop_t *, ide_drive_t *, u8, u8, unsigned long);
 
 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 *);
 
 int ide_taskfile_ioctl(ide_drive_t *, unsigned long);
 
-int ide_dev_read_id(ide_drive_t *, u8, u16 *);
+int ide_dev_read_id(ide_drive_t *, u8, u16 *, int);
 
 extern int ide_driveid_update(ide_drive_t *);
 extern int ide_config_drive_speed(ide_drive_t *, u8);