Commit 2101dbee authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] rework the reset code to fix posting and races

This isnt perfect, there is a race left somewhere still but its closer.
parent 0add1dfa
...@@ -1071,7 +1071,7 @@ EXPORT_SYMBOL(ide_execute_command); ...@@ -1071,7 +1071,7 @@ EXPORT_SYMBOL(ide_execute_command);
/* needed below */ /* 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 * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
...@@ -1188,8 +1188,7 @@ void check_dma_crc (ide_drive_t *drive) ...@@ -1188,8 +1188,7 @@ void check_dma_crc (ide_drive_t *drive)
void pre_reset (ide_drive_t *drive) 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->keep_settings) {
if (drive->using_dma) { if (drive->using_dma) {
...@@ -1223,14 +1222,20 @@ void pre_reset (ide_drive_t *drive) ...@@ -1223,14 +1222,20 @@ void pre_reset (ide_drive_t *drive)
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it, * (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals. * 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 int unit;
unsigned long flags; unsigned long flags;
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif;
ide_hwgroup_t *hwgroup = HWGROUP(drive); 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. */ /* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) { if (drive->media != ide_disk && !do_not_try_atapi) {
...@@ -1239,10 +1244,8 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ...@@ -1239,10 +1244,8 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
udelay (20); udelay (20);
hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
if (HWGROUP(drive)->handler != NULL) __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
BUG(); spin_unlock_irqrestore(&ide_lock, flags);
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
local_irq_restore(flags);
return ide_started; return ide_started;
} }
...@@ -1255,20 +1258,10 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ...@@ -1255,20 +1258,10 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
#if OK_TO_RESET_CONTROLLER #if OK_TO_RESET_CONTROLLER
if (!IDE_CONTROL_REG) { if (!IDE_CONTROL_REG) {
local_irq_restore(flags); spin_unlock_irqrestore(&ide_lock, flags);
return ide_stopped; 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, * Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset. * to mask unwanted interrupts from the interface during the reset.
...@@ -1278,23 +1271,21 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ...@@ -1278,23 +1271,21 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
* recover from reset very quickly, saving us the first 50ms wait time. * recover from reset very quickly, saving us the first 50ms wait time.
*/ */
/* set SRST and nIEN */ /* 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 */ /* more than enough time */
udelay(10); udelay(10);
if (drive->quirk_list == 2) { if (drive->quirk_list == 2) {
/* clear SRST and nIEN */ /* clear SRST and nIEN */
hwif->OUTB(drive->ctl, IDE_CONTROL_REG); hwif->OUTBSYNC(drive, drive->ctl, IDE_CONTROL_REG);
} else { } else {
/* clear SRST, leave nIEN */ /* 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 */ /* more than enough time */
udelay(10); udelay(10);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
if (HWGROUP(drive)->handler != NULL) __ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
BUG();
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
# endif
/* /*
* Some weird controller like resetting themselves to a strange * Some weird controller like resetting themselves to a strange
* state when the disks are reset this way. At least, the Winbond * state when the disks are reset this way. At least, the Winbond
...@@ -1302,71 +1293,22 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) ...@@ -1302,71 +1293,22 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
*/ */
if (hwif->resetproc != NULL) { if (hwif->resetproc != NULL) {
hwif->resetproc(drive); hwif->resetproc(drive);
# if 0
if (drive->failures) {
local_irq_restore(flags);
return ide_stopped;
}
# endif
} }
#endif /* OK_TO_RESET_CONTROLLER */ #endif /* OK_TO_RESET_CONTROLLER */
local_irq_restore(flags); spin_unlock_irqrestore(&ide_lock, flags);
return ide_started; return ide_started;
} }
#if 0
/* /*
* ide_do_reset() is the entry point to the drive/interface reset code. * 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 ide_do_reset (ide_drive_t *drive)
{ {
return do_reset1(drive, 0); 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); EXPORT_SYMBOL(ide_do_reset);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment