summaryrefslogtreecommitdiffstats
path: root/drivers/ide
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-10-13 17:47:49 +0200
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-10-13 17:47:49 +0200
commit74af21cf4d0ab67df53608753a443dc7904ec12e (patch)
tree0e5cbfdc12dbd00fcde2ccf08c7df59e3424ff11 /drivers/ide
parentfd553ce86893e0a54ec0d07d1f1d241f2fb2aef3 (diff)
ide: add __ide_wait_stat() helper
* Split off checking of the status register from ide_wait_stat() to __ide_wait_stat() helper. * Use the new helper in ide_config_drive_speed(). The only change in the functionality is that the function now fails if after 20 sec (WAIT_CMD) device is still busy (BUSY_STAT bit is set) while previously instead of failing the function continued with checking for the correct device status (which would give the device additional 10 usec to clear BUSY_STAT bit). * Remove stale comment for ide_config_drive_speed(). * Remove duplicate comment for ide_wait_stat() from <linux/ide.h>. Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide')
-rw-r--r--drivers/ide/ide-iops.c96
1 files changed, 44 insertions, 52 deletions
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index cf0678b6116..fb524cf175d 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -505,25 +505,19 @@ int wait_for_ready (ide_drive_t *drive, int timeout)
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
* of the "bad" bits, and if all is okay it returns 0. All other
- * cases return 1 after invoking ide_error() -- caller should just return.
+ * cases return error -- caller may then invoke ide_error().
*
* This routine should get fixed to not hog the cpu during extra long waits..
* That could be done by busy-waiting for the first jiffy or two, and then
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
- int i;
+ ide_hwif_t *hwif = drive->hwif;
unsigned long flags;
-
- /* bail early if we've exceeded max_failures */
- if (drive->max_failures && (drive->failures > drive->max_failures)) {
- *startstop = ide_stopped;
- return 1;
- }
+ int i;
+ u8 stat;
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
@@ -541,8 +535,8 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
break;
local_irq_restore(flags);
- *startstop = ide_error(drive, "status timeout", stat);
- return 1;
+ *rstat = stat;
+ return -EBUSY;
}
}
local_irq_restore(flags);
@@ -556,11 +550,39 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
*/
for (i = 0; i < 10; i++) {
udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+ if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+ *rstat = stat;
return 0;
+ }
}
- *startstop = ide_error(drive, "status error", stat);
- return 1;
+ *rstat = stat;
+ return -EFAULT;
+}
+
+/*
+ * In case of error returns error value after doing "*startstop = ide_error()".
+ * The caller should return the updated value of "startstop" in this case,
+ * "startstop" is unchanged when the function returns 0.
+ */
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+ int err;
+ u8 stat;
+
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
+ err = __ide_wait_stat(drive, good, bad, timeout, &stat);
+
+ if (err) {
+ char *s = (err == -EBUSY) ? "status timeout" : "status error";
+ *startstop = ide_error(drive, s, stat);
+ }
+
+ return err;
}
EXPORT_SYMBOL(ide_wait_stat);
@@ -778,15 +800,10 @@ int ide_driveid_update (ide_drive_t *drive)
#endif
}
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- int i, error = 1;
+ ide_hwif_t *hwif = drive->hwif;
+ int error;
u8 stat;
// while (HWGROUP(drive)->busy)
@@ -826,35 +843,10 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
- udelay(1);
- /*
- * Wait for drive to become non-BUSY
- */
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
- unsigned long flags, timeout;
- local_irq_set(flags);
- timeout = jiffies + WAIT_CMD;
- while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
- if (time_after(jiffies, timeout))
- break;
- }
- local_irq_restore(flags);
- }
- /*
- * Allow status to settle, then read it again.
- * A few rare drives vastly violate the 400ns spec here,
- * so we'll wait up to 10usec for a "good" status
- * rather than expensively fail things immediately.
- * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
- */
- for (i = 0; i < 10; i++) {
- udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
- error = 0;
- break;
- }
- }
+ error = __ide_wait_stat(drive, drive->ready_stat,
+ BUSY_STAT|DRQ_STAT|ERR_STAT,
+ WAIT_CMD, &stat);
SELECT_MASK(drive, 0);