patch-2.3.28 linux/drivers/block/ide.c
Next file: linux/drivers/block/pdc202xx.c
Previous file: linux/drivers/block/ide-tape.c
Back to the patch index
Back to the overall index
- Lines: 1451
- Date:
Fri Nov 12 10:12:11 1999
- Orig file:
v2.3.27/linux/drivers/block/ide.c
- Orig date:
Thu Nov 11 20:11:32 1999
diff -u --recursive --new-file v2.3.27/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.20 July 10, 1999
+ * linux/drivers/block/ide.c Version 6.21 November 9, 1999
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -106,15 +106,18 @@
* ATA-66 compliant, but have yet to determine a method
* of verification of the 80c cable presence.
* Specifically Promise's PDC20262 chipset.
+ * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old
+ * hat that clarified original low level driver design.
*
* Some additional driver compile-time options are in ./include/linux/ide.h
*
* To do, in likely order of completion:
* - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
-*/
+ *
+ */
-#define REVISION "Revision: 6.20"
-#define VERSION "Id: ide.c 6.20 1999/07/10"
+#define REVISION "Revision: 6.21"
+#define VERSION "Id: ide.c 6.21 1999/11/10"
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -186,7 +189,7 @@
* For really screwy hardware (hey, at least it *can* be used with Linux)
* we can enforce a minimum delay time between successive operations.
*/
-static unsigned long read_timer(void)
+static unsigned long read_timer (void)
{
unsigned long t, flags;
int i;
@@ -472,7 +475,7 @@
#if 0
udelay(1); /* need to guarantee 400ns since last command was issued */
#endif
- if (GET_STAT() & BUSY_STAT)
+ if (GET_STAT() & BUSY_STAT) /* Note: this may clear a pending IRQ!! */
return 0; /* drive busy: definitely not interrupting */
return 1; /* drive ready: *might* be interrupting */
}
@@ -480,7 +483,7 @@
/*
* This is our end_request replacement function.
*/
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup)
+void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
{
struct request *rq;
unsigned long flags;
@@ -511,18 +514,16 @@
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- spin_lock_irqsave(&hwgroup->spinlock, flags);
-#ifdef DEBUG
+ spin_lock_irqsave(&io_request_lock, flags);
if (hwgroup->handler != NULL) {
printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n",
drive->name, hwgroup->handler, handler);
}
-#endif
hwgroup->handler = handler;
hwgroup->expiry = expiry;
hwgroup->timer.expires = jiffies + timeout;
- add_timer(&(hwgroup->timer));
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ add_timer(&hwgroup->timer);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
/*
@@ -557,7 +558,7 @@
}
}
-static void do_reset1 (ide_drive_t *, int); /* needed below */
+static ide_startstop_t do_reset1 (ide_drive_t *, int); /* needed below */
/*
* atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
@@ -565,7 +566,7 @@
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
-static void atapi_reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
@@ -578,14 +579,14 @@
} else {
if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
- return; /* continue polling */
+ return ide_started; /* continue polling */
}
hwgroup->poll_timeout = 0; /* end of polling */
printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
- do_reset1 (drive, 1); /* do it the old fashioned way */
- return;
+ return do_reset1 (drive, 1); /* do it the old fashioned way */
}
hwgroup->poll_timeout = 0; /* done polling */
+ return ide_stopped;
}
/*
@@ -594,7 +595,7 @@
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
*/
-static void reset_pollfunc (ide_drive_t *drive)
+static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
ide_hwif_t *hwif = HWIF(drive);
@@ -603,7 +604,7 @@
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
- return; /* continue polling */
+ return ide_started; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
} else {
@@ -635,6 +636,7 @@
}
}
hwgroup->poll_timeout = 0; /* done polling */
+ return ide_stopped;
}
static void pre_reset (ide_drive_t *drive)
@@ -664,7 +666,7 @@
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
-static void 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;
@@ -683,7 +685,7 @@
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
__restore_flags (flags); /* local CPU only */
- return;
+ return ide_started;
}
/*
@@ -696,7 +698,7 @@
#if OK_TO_RESET_CONTROLLER
if (!IDE_CONTROL_REG) {
__restore_flags(flags);
- return;
+ return ide_stopped;
}
/*
* Note that we also set nIEN while resetting the device,
@@ -724,14 +726,15 @@
#endif /* OK_TO_RESET_CONTROLLER */
__restore_flags (flags); /* local CPU only */
+ return ide_started;
}
/*
* ide_do_reset() is the entry point to the drive/interface reset code.
*/
-void ide_do_reset (ide_drive_t *drive)
+ide_startstop_t ide_do_reset (ide_drive_t *drive)
{
- do_reset1 (drive, 0);
+ return do_reset1 (drive, 0);
}
/*
@@ -757,11 +760,8 @@
HWGROUP(drive)->rq = NULL;
rq->rq_status = RQ_INACTIVE;
spin_unlock_irqrestore(&io_request_lock, flags);
- save_flags(flags); /* all CPUs; overkill? */
- cli(); /* all CPUs; overkill? */
if (rq->sem != NULL)
up(rq->sem); /* inform originator that rq has been serviced */
- restore_flags(flags); /* all CPUs; overkill? */
}
/*
@@ -854,19 +854,19 @@
/*
* ide_error() takes action based on the error returned by the drive.
*/
-void ide_error (ide_drive_t *drive, const char *msg, byte stat)
+ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, byte stat)
{
struct request *rq;
byte err;
err = ide_dump_status(drive, msg, stat);
if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
- return;
+ return ide_stopped;
/* retry only "normal" I/O: */
if (rq->cmd == IDE_DRIVE_CMD) {
rq->errors = 1;
ide_end_drive_cmd(drive, stat, err);
- return;
+ return ide_stopped;
}
if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
rq->errors |= ERROR_RESET;
@@ -875,7 +875,7 @@
/* err has different meaning on cdrom and tape */
if (err == ABRT_ERR) {
if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
- return; /* some newer drives don't support WIN_SPECIFY */
+ return ide_stopped; /* some newer drives don't support WIN_SPECIFY */
} else if ((err & (ABRT_ERR | ICRC_ERR)) == (ABRT_ERR | ICRC_ERR))
; /* UDMA crc error -- just retry the operation */
else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */
@@ -897,19 +897,20 @@
} else {
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++rq->errors;
- ide_do_reset(drive);
- return;
- } else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+ return ide_do_reset(drive);
+ }
+ if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
drive->special.b.recalibrate = 1;
++rq->errors;
}
+ return ide_stopped;
}
/*
* Issue a simple drive command
* The drive must be selected beforehand.
*/
-void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
ide_set_handler (drive, handler, WAIT_CMD, NULL);
if (IDE_CONTROL_REG)
@@ -921,7 +922,7 @@
/*
* drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
*/
-static void drive_cmd_intr (ide_drive_t *drive)
+static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
byte *args = (byte *) rq->buffer;
@@ -938,17 +939,17 @@
udelay(100);
}
- if (OK_STAT(stat, READY_STAT, BAD_STAT))
- ide_end_drive_cmd (drive, stat, GET_ERR());
- else
- ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT))
+ return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
+ ide_end_drive_cmd (drive, stat, GET_ERR());
+ return ide_stopped;
}
/*
* do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
* commands to a drive. It used to do much more, but has been scaled back.
*/
-static inline void do_special (ide_drive_t *drive)
+static ide_startstop_t do_special (ide_drive_t *drive)
{
special_t *s = &drive->special;
@@ -961,11 +962,12 @@
if (tuneproc != NULL)
tuneproc(drive, drive->tune_req);
} else if (drive->driver != NULL) {
- DRIVER(drive)->special(drive);
+ return DRIVER(drive)->special(drive);
} else if (s->all) {
printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
s->all = 0;
}
+ return ide_stopped;
}
/*
@@ -979,12 +981,11 @@
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
-int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
-{
+int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
byte stat;
int i;
unsigned long flags;
-
+
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = GET_STAT()) & BUSY_STAT) {
__save_flags(flags); /* local CPU only */
@@ -993,7 +994,7 @@
while ((stat = GET_STAT()) & BUSY_STAT) {
if (0 < (signed long)(jiffies - timeout)) {
__restore_flags(flags); /* local CPU only */
- ide_error(drive, "status timeout", stat);
+ *startstop = ide_error(drive, "status timeout", stat);
return 1;
}
}
@@ -1011,7 +1012,7 @@
if (OK_STAT((stat = GET_STAT()), good, bad))
return 0;
}
- ide_error(drive, "status error", stat);
+ *startstop = ide_error(drive, "status error", stat);
return 1;
}
@@ -1019,7 +1020,7 @@
* execute_drive_cmd() issues a special drive command,
* usually initiated by ioctl() from the external hdparm program.
*/
-static void execute_drive_cmd (ide_drive_t *drive, struct request *rq)
+static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
{
byte *args = rq->buffer;
if (args) {
@@ -1033,11 +1034,11 @@
OUT_BYTE(args[2],IDE_FEATURE_REG);
OUT_BYTE(args[1],IDE_SECTOR_REG);
ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
- return;
+ return ide_started;
}
OUT_BYTE(args[2],IDE_FEATURE_REG);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
- return;
+ return ide_started;
} else {
/*
* NULL is actually a valid way of waiting for
@@ -1047,21 +1048,21 @@
printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
- return;
+ return ide_stopped;
}
}
/*
* start_request() initiates handling of a new I/O request
*/
-static inline void start_request (ide_drive_t *drive)
+static ide_startstop_t start_request (ide_drive_t *drive)
{
+ ide_startstop_t startstop;
unsigned long block, blockend;
struct request *rq = drive->queue;
unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
ide_hwif_t *hwif = HWIF(drive);
- ide__sti(); /* local CPU only */
#ifdef DEBUG
printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
#endif
@@ -1094,29 +1095,27 @@
#endif
SELECT_DRIVE(hwif, drive);
- if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
+ if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk("%s: drive not ready for command\n", drive->name);
- return;
+ return startstop;
}
if (!drive->special.all) {
if (rq->cmd == IDE_DRIVE_CMD) {
- execute_drive_cmd(drive, rq);
- return;
+ return execute_drive_cmd(drive, rq);
}
if (drive->driver != NULL) {
- DRIVER(drive)->do_request(drive, rq, block);
- return;
+ return (DRIVER(drive)->do_request(drive, rq, block));
}
printk("%s: media type %d not supported\n", drive->name, drive->media);
goto kill_rq;
}
- do_special(drive);
- return;
+ return do_special(drive);
kill_rq:
if (drive->driver != NULL)
DRIVER(drive)->end_request(0, HWGROUP(drive));
else
ide_end_request(0, HWGROUP(drive));
+ return ide_stopped;
}
/*
@@ -1177,22 +1176,54 @@
}
/*
- * Caller must have already acquired spinlock using *spinflags
+ * Issue a new request to a drive from hwgroup
+ * Caller must have already done spin_lock_irqsave(&io_request_lock, ..);
+ *
+ * A hwgroup is a serialized group of IDE interfaces. Usually there is
+ * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
+ * may have both interfaces in a single hwgroup to "serialize" access.
+ * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
+ * together into one hwgroup for serialized access.
+ *
+ * Note also that several hwgroups can end up sharing a single IRQ,
+ * possibly along with many other devices. This is especially common in
+ * PCI-based systems with off-board IDE controller cards.
+ *
+ * The IDE driver uses the single global io_request_lock spinlock to protect
+ * access to the request queues, and to protect the hwgroup->busy flag.
+ *
+ * The first thread into the driver for a particular hwgroup sets the
+ * hwgroup->busy flag to indicate that this hwgroup is now active,
+ * and then initiates processing of the top request from the request queue.
+ *
+ * Other threads attempting entry notice the busy setting, and will simply
+ * queue their new requests and exit immediately. Note that hwgroup->busy
+ * remains set even when the driver is merely awaiting the next interrupt.
+ * Thus, the meaning is "this hwgroup is busy processing a request".
+ *
+ * When processing of a request completes, the completing thread or IRQ-handler
+ * will start the next request from the queue. If no more work remains,
+ * the driver will clear the hwgroup->busy flag and exit.
+ *
+ * The io_request_lock (spinlock) is used to protect all access to the
+ * hwgroup->busy flag, but is otherwise not needed for most processing in
+ * the driver. This makes the driver much more friendlier to shared IRQs
+ * than previous designs, while remaining 100% (?) SMP safe and capable.
*/
-static void ide_do_request (ide_hwgroup_t *hwgroup, unsigned long *hwgroup_flags, int masked_irq)
+static void ide_do_request (ide_hwgroup_t *hwgroup)
{
struct blk_dev_struct *bdev;
ide_drive_t *drive;
ide_hwif_t *hwif;
- unsigned long io_flags;
+ ide_startstop_t startstop;
- hwgroup->busy = 1;
- while (hwgroup->handler == NULL) {
- spin_lock_irqsave(&io_request_lock, io_flags);
+ ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only: POSSIBLY BROKEN HERE(?) */
+
+ while (!hwgroup->busy) {
+ hwgroup->busy = 1;
drive = choose_drive(hwgroup);
if (drive == NULL) {
unsigned long sleep = 0;
-
hwgroup->rq = NULL;
drive = hwgroup->drive;
do {
@@ -1202,27 +1233,34 @@
if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
sleep = drive->sleep;
} while ((drive = drive->next) != hwgroup->drive);
- spin_unlock_irqrestore(&io_request_lock, io_flags);
if (sleep) {
+ /*
+ * Take a short snooze, and then wake up this hwgroup again.
+ * This gives other hwgroups on the same a chance to
+ * play fairly with us, just in case there are big differences
+ * in relative throughputs.. don't want to hog the cpu too much.
+ */
if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
sleep = jiffies + WAIT_MIN_SLEEP;
#if 1
if (hwgroup->timer.next || hwgroup->timer.prev)
printk("ide_set_handler: timer already active\n");
#endif
+ hwgroup->sleeping = 1; /* so that ide_timer_expiry knows what to do */
mod_timer(&hwgroup->timer, sleep);
+ /* we purposely leave hwgroup->busy==1 while sleeping */
} else {
/* Ugly, but how can we sleep for the lock otherwise? perhaps from tq_scheduler? */
ide_release_lock(&ide_lock); /* for atari only */
+ hwgroup->busy = 0;
}
- hwgroup->busy = 0;
- return;
+ return; /* no more work for this hwgroup (for now) */
}
hwif = HWIF(drive);
- if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif &&
- hwif->io_ports[IDE_CONTROL_OFFSET])
+ if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
/* set nIEN for previous hwif */
OUT_BYTE(hwgroup->drive->ctl|2, hwgroup->hwif->io_ports[IDE_CONTROL_OFFSET]);
+ }
hwgroup->hwif = hwif;
hwgroup->drive = drive;
drive->sleep = 0;
@@ -1232,39 +1270,13 @@
if (bdev->current_request == &bdev->plug) /* FIXME: paranoia */
printk("%s: Huh? nuking plugged queue\n", drive->name);
bdev->current_request = hwgroup->rq = drive->queue;
- spin_unlock_irqrestore(&io_request_lock, io_flags);
-
-#if 0
- if (hwif->irq != masked_irq)
- disable_irq_nosync(hwif->irq);
- spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
- start_request(drive);
- spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
- if (hwif->irq != masked_irq)
- enable_irq(hwif->irq);
-#else
-
- if (masked_irq && hwif->irq != masked_irq) {
- printk("%s: (disable_irq) %smasked_irq %d\n",
- drive->name,
- masked_irq ? "" : "un_", hwif->irq);
-
-#if 0
- disable_irq(hwif->irq);
-#else
- disable_irq_nosync(hwif->irq);
-#endif
- }
- spin_unlock_irqrestore(&hwgroup->spinlock, *hwgroup_flags);
- start_request(drive);
- spin_lock_irqsave(&hwgroup->spinlock, *hwgroup_flags);
- if (masked_irq && hwif->irq != masked_irq) {
- printk("%s: (enable_irq) %smasked_irq %d\n",
- drive->name,
- masked_irq ? "" : "un_", hwif->irq);
- enable_irq(hwif->irq);
- }
-#endif
+ spin_unlock(&io_request_lock);
+ if (!hwif->serialized) /* play it safe with buggy hardware */
+ ide__sti();
+ startstop = start_request(drive);
+ spin_lock_irq(&io_request_lock);
+ if (startstop == ide_stopped)
+ hwgroup->busy = 0;
}
}
@@ -1278,179 +1290,158 @@
return &hwif->drives[DEVICE_NR(dev) & 1].queue;
}
-/*
- * do_hwgroup_request() invokes ide_do_request() after claiming hwgroup->busy.
- */
-static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&hwgroup->spinlock, flags);
- if (hwgroup->busy) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- return;
- }
- del_timer(&hwgroup->timer);
- ide_get_lock(&ide_lock, ide_intr, hwgroup); /* for atari only */
- ide_do_request(hwgroup, &flags, 0);
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-}
-
-/*
- * ll_rw_blk.c invokes our do_idex_request() function
- * with the io_request_spinlock already grabbed.
- * Since we need to do our own spinlock's internally,
- * on paths that don't necessarily originate through the
- * do_idex_request() path, we have to undo the spinlock on entry,
- * and restore it again on exit.
- * Fortunately, this is mostly a nop for non-SMP kernels.
- */
-static inline void unlock_do_hwgroup_request (ide_hwgroup_t *hwgroup)
-{
- spin_unlock(&io_request_lock);
- do_hwgroup_request (hwgroup);
- spin_lock_irq(&io_request_lock);
-}
-
void do_ide0_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[0].hwgroup);
+ ide_do_request (ide_hwifs[0].hwgroup);
}
#if MAX_HWIFS > 1
void do_ide1_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[1].hwgroup);
+ ide_do_request (ide_hwifs[1].hwgroup);
}
#endif /* MAX_HWIFS > 1 */
#if MAX_HWIFS > 2
void do_ide2_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[2].hwgroup);
+ ide_do_request (ide_hwifs[2].hwgroup);
}
#endif /* MAX_HWIFS > 2 */
#if MAX_HWIFS > 3
void do_ide3_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[3].hwgroup);
+ ide_do_request (ide_hwifs[3].hwgroup);
}
#endif /* MAX_HWIFS > 3 */
#if MAX_HWIFS > 4
void do_ide4_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[4].hwgroup);
+ ide_do_request (ide_hwifs[4].hwgroup);
}
#endif /* MAX_HWIFS > 4 */
#if MAX_HWIFS > 5
void do_ide5_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[5].hwgroup);
+ ide_do_request (ide_hwifs[5].hwgroup);
}
#endif /* MAX_HWIFS > 5 */
#if MAX_HWIFS > 6
void do_ide6_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[6].hwgroup);
+ ide_do_request (ide_hwifs[6].hwgroup);
}
#endif /* MAX_HWIFS > 6 */
#if MAX_HWIFS > 7
void do_ide7_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[7].hwgroup);
+ ide_do_request (ide_hwifs[7].hwgroup);
}
#endif /* MAX_HWIFS > 7 */
#if MAX_HWIFS > 8
void do_ide8_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[8].hwgroup);
+ ide_do_request (ide_hwifs[8].hwgroup);
}
#endif /* MAX_HWIFS > 8 */
#if MAX_HWIFS > 9
void do_ide9_request (void)
{
- unlock_do_hwgroup_request (ide_hwifs[9].hwgroup);
+ ide_do_request (ide_hwifs[9].hwgroup);
}
#endif /* MAX_HWIFS > 9 */
-static void start_next_request (ide_hwgroup_t *hwgroup, int masked_irq)
-{
- unsigned long flags;
- ide_drive_t *drive;
-
- spin_lock_irqsave(&hwgroup->spinlock, flags);
- if (hwgroup->handler != NULL) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- return;
- }
- drive = hwgroup->drive;
- set_recovery_timer(HWIF(drive));
- drive->service_time = jiffies - drive->service_start;
- ide_do_request(hwgroup, &flags, masked_irq);
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
-}
-
+/*
+ * ide_timer_expiry() is our timeout function for all drive operations.
+ * But note that it can also be invoked as a result of a "sleep" operation
+ * triggered by the mod_timer() call in ide_do_request.
+ */
void ide_timer_expiry (unsigned long data)
{
- ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
- ide_drive_t *drive;
- ide_handler_t *handler;
- ide_expiry_t *expiry;
- unsigned long flags;
- unsigned long wait;
+ ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
+ ide_handler_t *handler;
+ ide_expiry_t *expiry;
+ unsigned long flags;
+ unsigned long wait;
- spin_lock_irqsave(&hwgroup->spinlock, flags);
- drive = hwgroup->drive;
- if ((handler = hwgroup->handler) == NULL) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- do_hwgroup_request(hwgroup);
- return;
- }
-
- hwgroup->busy = 1; /* should already be "1" */
+ spin_lock_irqsave(&io_request_lock, flags);
+ del_timer(&hwgroup->timer);
- if ((expiry = hwgroup->expiry) != NULL) {
- /* continue */
- if ((wait = expiry(drive)) != 0) {
- /* reset timer */
- hwgroup->timer.expires = jiffies + wait;
- add_timer(&(hwgroup->timer));
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- return;
+ if ((handler = hwgroup->handler) == NULL) {
+ /*
+ * Either a marginal timeout occured
+ * (got the interrupt just as timer expired),
+ * or we were "sleeping" to give other devices a chance.
+ * Either way, we don't really want to complain about anything.
+ */
+ if (hwgroup->sleeping) {
+ hwgroup->sleeping = 0;
+ hwgroup->busy = 0;
}
- }
-
- hwgroup->handler = NULL;
-
- if (hwgroup->poll_timeout != 0) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- handler(drive);
- } else if (drive_is_ready(drive)) {
- printk("%s: lost interrupt\n", drive->name);
- (void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- handler(drive);
} else {
- if (drive->waiting_for_dma) {
- (void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
- printk("%s: timeout waiting for DMA\n", drive->name);
- /*
- * need something here for HPT34X.......AMH
- * irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }
- */
- (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
+ ide_drive_t *drive = hwgroup->drive;
+ hwgroup->handler = NULL;
+ if (!drive) {
+ printk("ide_timer_expiry: hwgroup->drive was NULL\n");
+ } else {
+ ide_hwif_t *hwif;
+ ide_startstop_t startstop;
+ if (!hwgroup->busy) {
+ hwgroup->busy = 1; /* paranoia */
+ printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+ }
+ if ((expiry = hwgroup->expiry) != NULL) {
+ /* continue */
+ if ((wait = expiry(drive)) != 0) {
+ /* reset timer */
+ hwgroup->timer.expires = jiffies + wait;
+ add_timer(&hwgroup->timer);
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ }
+ /*
+ * We need to simulate a real interrupt when invoking
+ * the handler() function, which means we need to globally
+ * mask the specific IRQ:
+ */
+ spin_unlock(&io_request_lock);
+ hwif = HWIF(drive);
+ disable_irq(hwif->irq);
+ __cli(); /* local CPU only, as if we were handling an interrupt */
+ if (hwgroup->poll_timeout != 0) {
+ startstop = handler(drive);
+ } else if (drive_is_ready(drive)) {
+ if (drive->waiting_for_dma)
+ (void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);
+ (void)ide_ack_intr(hwif);
+ printk("%s: lost interrupt\n", drive->name);
+ startstop = handler(drive);
+ } else {
+ if (drive->waiting_for_dma) {
+ (void) hwgroup->hwif->dmaproc(ide_dma_end, drive);
+ printk("%s: timeout waiting for DMA\n", drive->name);
+ (void) hwgroup->hwif->dmaproc(ide_dma_timeout, drive);
+ }
+ startstop = ide_error(drive, "irq timeout", GET_STAT());
+ }
+ set_recovery_timer(hwif);
+ drive->service_time = jiffies - drive->service_start;
+ enable_irq(hwif->irq);
+ spin_lock_irq(&io_request_lock);
+ if (startstop == ide_stopped)
+ hwgroup->busy = 0;
}
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
- ide_error(drive, "irq timeout", GET_STAT());
}
- start_next_request(hwgroup, 0);
+ ide_do_request(hwgroup);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
/*
@@ -1500,6 +1491,7 @@
}
} while ((hwif = hwif->next) != hwgroup->hwif);
}
+
/*
* entry point for all interrupts, caller does __cli() for us
*/
@@ -1510,13 +1502,13 @@
ide_hwif_t *hwif;
ide_drive_t *drive;
ide_handler_t *handler;
+ ide_startstop_t startstop;
- __cli(); /* local CPU only */
- spin_lock_irqsave(&hwgroup->spinlock, flags);
+ spin_lock_irqsave(&io_request_lock, flags);
hwif = hwgroup->hwif;
if (!ide_ack_intr(hwif)) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
@@ -1542,29 +1534,70 @@
* so we can safely try to do something about it:
*/
unexpected_intr(irq, hwgroup);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ } else {
+ /*
+ * Whack the status register, just in case we have a leftover pending IRQ.
+ *
+ * Unless we are some version of a Promise Ultra66 :: PDC20262.
+ * We will hang like a rock....
+ */
+ byte skip_status = ((hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20262) ||
+ (hwif->pci_dev->device == PCI_DEVICE_ID_TTI_HPT366)) ? 1 : 0;
+ if (!skip_status)
+ (void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+#endif /* CONFIG_BLK_DEV_IDEPCI */
}
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
drive = hwgroup->drive;
- if (!drive || !drive_is_ready(drive)) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ if (!drive) {
+ /*
+ * This should NEVER happen, and there isn't much we could do about it here.
+ */
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
+ if (!drive_is_ready(drive)) {
+ /*
+ * This happens regularly when we share a PCI IRQ with another device.
+ * Unfortunately, it can also happen with some buggy drives that trigger
+ * the IRQ before their status register is up to date. Hopefully we have
+ * enough advance overhead that the latter isn't a problem.
+ */
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+ if (!hwgroup->busy) {
+ hwgroup->busy = 1; /* paranoia */
+ printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+ }
hwgroup->handler = NULL;
- del_timer(&(hwgroup->timer));
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ del_timer(&hwgroup->timer);
+ spin_unlock(&io_request_lock);
if (drive->unmask)
ide__sti(); /* local CPU only */
- handler(drive); /* service this interrupt, may set handler for next interrupt */
+ startstop = handler(drive); /* service this interrupt, may set handler for next interrupt */
+ spin_lock_irq(&io_request_lock);
/*
* Note that handler() may have set things up for another
* interrupt to occur soon, but it cannot happen until
* we exit from this routine, because it will be the
- * same irq as is currently being serviced here,
- * and Linux won't allow another (on any CPU) until we return.
+ * same irq as is currently being serviced here, and Linux
+ * won't allow another of the same (on any CPU) until we return.
*/
- start_next_request(hwgroup, hwif->irq);
+ set_recovery_timer(HWIF(drive));
+ drive->service_time = jiffies - drive->service_start;
+ if (startstop == ide_stopped) {
+ if (hwgroup->handler == NULL) { /* paranoia */
+ hwgroup->busy = 0;
+ ide_do_request(hwgroup);
+ } else {
+ printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);
+ }
+ }
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
/*
@@ -1649,7 +1682,6 @@
rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
if (action == ide_wait)
rq->sem = &sem;
-
spin_lock_irqsave(&io_request_lock, flags);
cur_rq = drive->queue;
if (cur_rq == NULL || action == ide_preempt) {
@@ -1665,13 +1697,14 @@
rq->next = cur_rq->next;
cur_rq->next = rq;
}
+ ide_do_request(hwgroup);
spin_unlock_irqrestore(&io_request_lock, flags);
- do_hwgroup_request(hwgroup);
if (action == ide_wait) {
- down(&sem); /* wait for it to be serviced */
- rq->sem = NULL;
+ down(&sem); /* wait for it to be serviced */
+ return rq->errors ? -EIO : 0; /* return -EIO if errors */
}
- return rq->errors ? -EIO : 0; /* return -EIO if errors */
+ return 0;
+
}
/*
@@ -1682,7 +1715,7 @@
* usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit.
*/
-int ide_revalidate_disk(kdev_t i_rdev)
+int ide_revalidate_disk (kdev_t i_rdev)
{
ide_drive_t *drive;
ide_hwgroup_t *hwgroup;
@@ -1694,14 +1727,14 @@
major = MAJOR(i_rdev);
minor = drive->select.b.unit << PARTN_BITS;
hwgroup = HWGROUP(drive);
- spin_lock_irqsave(&hwgroup->spinlock, flags);
+ spin_lock_irqsave(&io_request_lock, flags);
if (drive->busy || (drive->usage > 1)) {
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return -EBUSY;
};
drive->busy = 1;
MOD_INC_USE_COUNT;
- spin_unlock_irqrestore(&hwgroup->spinlock, flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
for (p = 0; p < (1<<PARTN_BITS); ++p) {
if (drive->part[p].nr_sects > 0) {
@@ -1767,7 +1800,7 @@
#endif /* CONFIG_KMOD */
}
-static int ide_open(struct inode * inode, struct file * filp)
+static int ide_open (struct inode * inode, struct file * filp)
{
ide_drive_t *drive;
int rc;
@@ -1807,7 +1840,7 @@
* Releasing a block device means we sync() it, so that it can safely
* be forgotten about...
*/
-static int ide_release(struct inode * inode, struct file * file)
+static int ide_release (struct inode * inode, struct file * file)
{
ide_drive_t *drive;
@@ -1821,7 +1854,7 @@
return 0;
}
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
{
if (!drive->present || drive->busy || drive->usage)
goto abort;
@@ -1979,6 +2012,7 @@
init_hwif_data (index); /* restore hwif data to pristine status */
hwif->hwgroup = old_hwif.hwgroup;
hwif->tuneproc = old_hwif.tuneproc;
+ hwif->resetproc = old_hwif.resetproc;
hwif->dmaproc = old_hwif.dmaproc;
hwif->dma_base = old_hwif.dma_base;
hwif->dma_extra = old_hwif.dma_extra;
@@ -2089,7 +2123,7 @@
return ide_register_hw(&hw, NULL);
}
-void ide_add_setting(ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
+void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set)
{
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL;
@@ -2115,7 +2149,7 @@
kfree(setting);
}
-void ide_remove_setting(ide_drive_t *drive, char *name)
+void ide_remove_setting (ide_drive_t *drive, char *name)
{
ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting;
@@ -2128,7 +2162,7 @@
kfree(setting);
}
-static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd)
+static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd)
{
ide_settings_t *setting = drive->settings;
@@ -2140,7 +2174,7 @@
return setting;
}
-ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name)
+ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name)
{
ide_settings_t *setting = drive->settings;
@@ -2152,7 +2186,7 @@
return setting;
}
-static void auto_remove_settings(ide_drive_t *drive)
+static void auto_remove_settings (ide_drive_t *drive)
{
ide_settings_t *setting;
repeat:
@@ -2166,13 +2200,13 @@
}
}
-int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting)
+int ide_read_setting (ide_drive_t *drive, ide_settings_t *setting)
{
int val = -EINVAL;
unsigned long flags;
if ((setting->rw & SETTING_READ)) {
- spin_lock_irqsave(&HWGROUP(drive)->spinlock, flags);
+ spin_lock_irqsave(&io_request_lock, flags);
switch(setting->data_type) {
case TYPE_BYTE:
val = *((u8 *) setting->data);
@@ -2185,7 +2219,7 @@
val = *((u32 *) setting->data);
break;
}
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
return val;
}
@@ -2195,20 +2229,29 @@
ide_hwgroup_t *hwgroup = HWGROUP(drive);
unsigned long timeout = jiffies + (3 * HZ);
- spin_lock_irqsave(&hwgroup->spinlock, *flags);
+ spin_lock_irqsave(&io_request_lock, *flags);
while (hwgroup->busy) {
- spin_unlock_irqrestore(&hwgroup->spinlock, *flags);
- __sti(); /* local CPU only; needed for jiffies */
+ unsigned long lflags;
+ spin_unlock_irqrestore(&io_request_lock, *flags);
+ __save_flags(lflags); /* local CPU only */
+ __sti(); /* local CPU only; needed for jiffies */
if (0 < (signed long)(jiffies - timeout)) {
+ __restore_flags(lflags); /* local CPU only */
printk("%s: channel busy\n", drive->name);
return -EBUSY;
}
- spin_lock_irqsave(&hwgroup->spinlock, *flags);
+ __restore_flags(lflags); /* local CPU only */
+ spin_lock_irqsave(&io_request_lock, *flags);
}
return 0;
}
-int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val)
+/*
+ * FIXME: This should be changed to enqueue a special request
+ * to the driver to change settings, and then wait on a sema for completion.
+ * The current scheme of polling is kludgey, though safe enough.
+ */
+int ide_write_setting (ide_drive_t *drive, ide_settings_t *setting, int val)
{
unsigned long flags;
int i;
@@ -2240,7 +2283,7 @@
*p = val;
break;
}
- spin_unlock_irqrestore(&HWGROUP(drive)->spinlock, flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return 0;
}
@@ -2254,7 +2297,7 @@
return 0;
}
-static int set_using_dma(ide_drive_t *drive, int arg)
+static int set_using_dma (ide_drive_t *drive, int arg)
{
if (!drive->driver || !DRIVER(drive)->supports_dma)
return -EPERM;
@@ -2265,7 +2308,7 @@
return 0;
}
-static int set_pio_mode(ide_drive_t *drive, int arg)
+static int set_pio_mode (ide_drive_t *drive, int arg)
{
struct request rq;
@@ -2280,7 +2323,7 @@
return 0;
}
-void ide_add_generic_settings(ide_drive_t *drive)
+void ide_add_generic_settings (ide_drive_t *drive)
{
/*
* drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function
@@ -2325,136 +2368,6 @@
while (0 < (signed long)(timeout - jiffies));
}
-int ide_config_drive_speed (ide_drive_t *drive, byte speed)
-{
- struct hd_driveid *id = drive->id;
- unsigned long flags;
- int err;
-
- __save_flags(flags); /* local CPU only */
- __cli(); /* local CPU only */
-
- /*
- * Don't use ide_wait_cmd here - it will
- * attempt to set_geometry and recalibrate,
- * but for some reason these don't work at
- * this point (lost interrupt).
- */
- SELECT_DRIVE(HWIF(drive), drive);
- if (IDE_CONTROL_REG)
- OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
- OUT_BYTE(speed, IDE_NSECTOR_REG);
- OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG);
- OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG);
-
- err = ide_wait_stat(drive, DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT, WAIT_CMD);
-
-#if 0
- if (IDE_CONTROL_REG)
- OUT_BYTE(drive->ctl, IDE_CONTROL_REG);
-#endif
-
- __restore_flags(flags); /* local CPU only */
-
- switch(speed) {
- case XFER_UDMA_4:
- if (!((id->dma_ultra >> 8) & 16)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x1010;
- }
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_UDMA_3:
- if (!((id->dma_ultra >> 8) & 8)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0808;
- }
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_UDMA_2:
- if (!((id->dma_ultra >> 8) & 4)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0404;
- }
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_UDMA_1:
- if (!((id->dma_ultra >> 8) & 2)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0202;
- }
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_UDMA_0:
- if (!((id->dma_ultra >> 8) & 1)) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_ultra |= 0x0101;
- }
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_MW_DMA_2:
- drive->id->dma_ultra &= ~0xFF00;
- if (!((id->dma_mword >> 8) & 4)) {
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_mword |= 0x0404;
- }
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_MW_DMA_1:
- drive->id->dma_ultra &= ~0xFF00;
- if (!((id->dma_mword >> 8) & 2)) {
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_mword |= 0x0202;
- }
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_MW_DMA_0:
- drive->id->dma_ultra &= ~0xFF00;
- if (!((id->dma_mword >> 8) & 1)) {
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_mword |= 0x0101;
- }
- drive->id->dma_1word &= ~0x0F00;
- break;
- case XFER_SW_DMA_2:
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- if (!((id->dma_1word >> 8) & 4)) {
- drive->id->dma_1word &= ~0x0F00;
- drive->id->dma_1word |= 0x0404;
- }
- break;
- case XFER_SW_DMA_1:
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- if (!((id->dma_1word >> 8) & 2)) {
- drive->id->dma_1word &= ~0x0F00;
- drive->id->dma_1word |= 0x0202;
- }
- break;
- case XFER_SW_DMA_0:
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- if (!((id->dma_1word >> 8) & 1)) {
- drive->id->dma_1word &= ~0x0F00;
- drive->id->dma_1word |= 0x0101;
- }
- break;
- default:
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- break;
- }
-
- return(err);
-}
-
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -2509,8 +2422,7 @@
return -EINVAL;
if (drive->id == NULL)
return -ENOMSG;
- if (copy_to_user((char *)arg, (char *)drive->id,
- (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
+ if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
return -EFAULT;
return 0;
@@ -2537,28 +2449,16 @@
return -ENOMEM;
memcpy(argbuf, args, 4);
}
- if ((((byte *)arg)[0] == WIN_SETFEATURES) &&
- (((byte *)arg)[1] > 66) &&
- (((byte *)arg)[2] == 3)) {
- if (!HWIF(drive)->udma_four) {
- printk("%s: Speed warnings UDMA 3/4 is not functional.\n", HWIF(drive)->name);
- goto abort;
- }
- if ((drive->id->word93 & 0x2000) == 0) {
- printk("%s: Speed warnings UDMA 3/4 is not functional.\n", drive->name);
- goto abort;
- }
- }
+ if (ide_ata66_check(drive, args[0], args[1], args[2]))
+ goto abort;
+
err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
- if (!err &&
- (((byte *)arg)[0] == WIN_SETFEATURES) &&
- (((byte *)arg)[1] >= 16) &&
- (((byte *)arg)[2] == 3) &&
- (drive->id->dma_ultra ||
- drive->id->dma_mword ||
- drive->id->dma_1word)) {
- /*
+ if (!err && set_transfer(drive, args[0], args[1], args[2])) {
+
+#if 1
+ ide_driveid_update(drive);
+#else /*
* Re-read drive->id for possible DMA mode
* change (copied from ide-probe.c)
*/
@@ -2602,6 +2502,7 @@
#endif
kfree(id);
}
+#endif
}
abort:
if (copy_to_user((void *)arg, argbuf, argsize))
@@ -2694,32 +2595,6 @@
}
/*
- *
- */
-char *ide_xfer_verbose (byte xfer_rate) {
- switch(xfer_rate) {
- case XFER_UDMA_4: return("UDMA 4");
- case XFER_UDMA_3: return("UDMA 3");
- case XFER_UDMA_2: return("UDMA 2");
- case XFER_UDMA_1: return("UDMA 1");
- case XFER_UDMA_0: return("UDMA 0");
- case XFER_MW_DMA_2: return("MW DMA 2");
- case XFER_MW_DMA_1: return("MW DMA 1");
- case XFER_MW_DMA_0: return("MW DMA 0");
- case XFER_SW_DMA_2: return("SW DMA 2");
- case XFER_SW_DMA_1: return("SW DMA 1");
- case XFER_SW_DMA_0: return("SW DMA 0");
- case XFER_PIO_4: return("PIO 4");
- case XFER_PIO_3: return("PIO 3");
- case XFER_PIO_2: return("PIO 2");
- case XFER_PIO_1: return("PIO 1");
- case XFER_PIO_0: return("PIO 0");
- case XFER_PIO_SLOW: return("PIO SLOW");
- default: return("XFER ERROR");
- }
-}
-
-/*
* stridx() returns the offset of c within s,
* or -1 if c is '\0' or not found within s.
*/
@@ -2796,7 +2671,7 @@
* "hdx=nowerr" : ignore the WRERR_STAT bit on this drive
* "hdx=cdrom" : drive is present, and is a cdrom drive
* "hdx=cyl,head,sect" : disk drive is present, with specified geometry
- * "hdx=noremap" : do not remap 0->1 even though EZD was detected
+ * "hdx=noremap" : do not remap 0->1 even though EZD was detected
* "hdx=autotune" : driver will attempt to tune interface speed
* to the fastest PIO mode supported,
* if possible for this drive only.
@@ -3198,6 +3073,14 @@
}
/*
+ * __setup("ide", ide_setup);
+ * #ifdef CONFIG_BLK_DEV_VIA82CXXX
+ * __setup("splitfifo", ide_setup);
+ * #endif
+ * __setup("hd", ide_setup);
+ */
+
+/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
*/
static void __init probe_for_hwifs (void)
@@ -3332,9 +3215,10 @@
return ide_unregister_subdriver(drive);
}
-static void default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
{
ide_end_request(0, HWGROUP(drive));
+ return ide_stopped;
}
static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
@@ -3372,12 +3256,13 @@
return 0x7fffffff; /* cdrom or tape */
}
-static void default_special (ide_drive_t *drive)
+static ide_startstop_t default_special (ide_drive_t *drive)
{
special_t *s = &drive->special;
s->all = 0;
drive->mult_req = 0;
+ return ide_stopped;
}
static void setup_driver_defaults (ide_drive_t *drive)
@@ -3577,7 +3462,6 @@
EXPORT_SYMBOL(ide_cmd);
EXPORT_SYMBOL(ide_wait_cmd);
EXPORT_SYMBOL(ide_delay_50ms);
-EXPORT_SYMBOL(ide_config_drive_speed);
EXPORT_SYMBOL(ide_stall_queue);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(ide_add_proc_entries);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)