Messages in this thread Patch in this message | | | Date | Fri, 21 Mar 2003 20:41:39 GMT | From | Alan Cox <> | Subject | PATCH: rework the reset code tof ix posting and races |
| |
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/
| |