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);
/* 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
......@@ -1188,8 +1188,7 @@ void check_dma_crc (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->using_dma) {
......@@ -1223,14 +1222,20 @@ void pre_reset (ide_drive_t *drive)
* (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) {
......@@ -1239,10 +1244,8 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
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;
}
......@@ -1255,20 +1258,10 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
#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.
......@@ -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.
*/
/* 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
......@@ -1302,71 +1293,22 @@ ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
*/
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);
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