PATCH: rework the reset code tof ix posting and races

From: Alan Cox (alan@lxorguk.ukuu.org.uk)
Date: Fri Mar 21 2003 - 15:41:39 EST


This isnt perfect, there is a race left somewhere still but its closer.

diff -u --new-file --recursive --exclude-from /usr/src/exclude linux-2.5.65/drivers/ide/ide-iops.c linux-2.5.65-ac2/drivers/ide/ide-iops.c
--- linux-2.5.65/drivers/ide/ide-iops.c 2003-03-18 16:46:48.000000000 +0000
+++ linux-2.5.65-ac2/drivers/ide/ide-iops.c 2003-03-07 18:43:58.000000000 +0000
@@ -1050,7 +1071,7 @@
 
 
 /* needed below */
-ide_startstop_t do_reset1 (ide_drive_t *, int);
+static ide_startstop_t do_reset1 (ide_drive_t *, int);
 
 /*
  * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
@@ -1167,8 +1188,7 @@
 
 void pre_reset (ide_drive_t *drive)
 {
- if (drive->driver != NULL)
- DRIVER(drive)->pre_reset(drive);
+ DRIVER(drive)->pre_reset(drive);
 
         if (!drive->keep_settings) {
                 if (drive->using_dma) {
@@ -1202,14 +1222,20 @@
  * (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
  * we set a timer to poll at 50ms intervals.
  */
-ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
+static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
 {
         unsigned int unit;
         unsigned long flags;
- ide_hwif_t *hwif = HWIF(drive);
- ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ ide_hwif_t *hwif;
+ ide_hwgroup_t *hwgroup;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif = HWIF(drive);
+ hwgroup = HWGROUP(drive);
 
- local_irq_save(flags);
+ /* We must not reset with running handlers */
+ if(hwgroup->handler != NULL)
+ BUG();
 
         /* For an ATAPI device, first try an ATAPI SRST. */
         if (drive->media != ide_disk && !do_not_try_atapi) {
@@ -1218,10 +1244,8 @@
                 udelay (20);
                 hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
                 hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- if (HWGROUP(drive)->handler != NULL)
- BUG();
- ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
- local_irq_restore(flags);
+ __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
+ spin_unlock_irqrestore(&ide_lock, flags);
                 return ide_started;
         }
 
@@ -1234,20 +1258,10 @@
 
 #if OK_TO_RESET_CONTROLLER
         if (!IDE_CONTROL_REG) {
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&ide_lock, flags);
                 return ide_stopped;
         }
 
-# if 0
- {
- u8 control = hwif->INB(IDE_CONTROL_REG);
- control |= 0x04;
- hwif->OUTB(control,IDE_CONTROL_REG);
- udelay(30);
- control &= 0xFB;
- hwif->OUTB(control, IDE_CONTROL_REG);
- }
-# else
         /*
          * Note that we also set nIEN while resetting the device,
          * to mask unwanted interrupts from the interface during the reset.
@@ -1257,23 +1271,21 @@
          * recover from reset very quickly, saving us the first 50ms wait time.
          */
         /* set SRST and nIEN */
- hwif->OUTB(drive->ctl|6,IDE_CONTROL_REG);
+ hwif->OUTBSYNC(drive, drive->ctl|6,IDE_CONTROL_REG);
         /* more than enough time */
         udelay(10);
         if (drive->quirk_list == 2) {
                 /* clear SRST and nIEN */
- hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+ hwif->OUTBSYNC(drive, drive->ctl, IDE_CONTROL_REG);
         } else {
                 /* clear SRST, leave nIEN */
- hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+ hwif->OUTBSYNC(drive, drive->ctl|2, IDE_CONTROL_REG);
         }
         /* more than enough time */
         udelay(10);
         hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
- if (HWGROUP(drive)->handler != NULL)
- BUG();
- ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
-# endif
+ __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
+
         /*
          * Some weird controller like resetting themselves to a strange
          * state when the disks are reset this way. At least, the Winbond
@@ -1281,71 +1293,22 @@
          */
         if (hwif->resetproc != NULL) {
                 hwif->resetproc(drive);
-
-# if 0
- if (drive->failures) {
- local_irq_restore(flags);
- return ide_stopped;
- }
-# endif
         }
-
+
 #endif /* OK_TO_RESET_CONTROLLER */
 
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&ide_lock, flags);
         return ide_started;
 }
 
-#if 0
 /*
  * ide_do_reset() is the entry point to the drive/interface reset code.
  */
+
 ide_startstop_t ide_do_reset (ide_drive_t *drive)
 {
         return do_reset1(drive, 0);
 }
-#else
-/*
- * ide_do_reset() is the entry point to the drive/interface reset code.
- */
-ide_startstop_t ide_do_reset (ide_drive_t *drive)
-{
- ide_startstop_t start_stop = ide_started;
-# if 0
- u8 tmp_dma = drive->using_dma;
- u8 cspeed = drive->current_speed;
- u8 unmask = drive->unmask;
-# endif
-
- if (HWGROUP(drive)->handler != NULL) {
- unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
- HWGROUP(drive)->handler = NULL;
- del_timer(&HWGROUP(drive)->timer);
- spin_unlock_irqrestore(&ide_lock, flags);
- }
-
- start_stop = do_reset1(drive, 0);
-# if 0
- /*
- * check for suspend-spindown flag,
- * to attempt a restart or spinup of device.
- */
- if (drive->suspend_reset) {
- /*
- * APM WAKE UP todo !!
- * int nogoodpower = 1;
- * while(nogoodpower) {
- * check_power1() or check_power2()
- * nogoodpower = 0;
- * }
- * HWIF(drive)->multiproc(drive);
- */
-# endif
-
- return start_stop;
-}
-#endif
 
 EXPORT_SYMBOL(ide_do_reset);
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Mar 23 2003 - 22:00:37 EST