patch-1.3.46 linux/drivers/block/ide.c
Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ide-tape.h
Back to the patch index
Back to the overall index
- Lines: 1221
- Date:
Mon Dec 11 08:49:54 1995
- Orig file:
v1.3.45/linux/drivers/block/ide.c
- Orig date:
Mon Nov 27 12:48:28 1995
diff -u --recursive --new-file v1.3.45/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 5.18 Nov 16, 1995
+ * linux/drivers/block/ide.c Version 5.22 Dec 10, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
@@ -170,6 +170,14 @@
* Version 5.18 new CMD640 code, moved to cmd640.c, #include'd for now
* new UMC8672 code, moved to umc8672.c, #include'd for now
* disallow turning on DMA when h/w not capable of DMA
+ * Version 5.19 fix potential infinite timeout on resets
+ * extend reset poll into a general purpose polling scheme
+ * add atapi tape drive support from Gadi Oxman
+ * simplify exit from _intr routines -- no IDE_DO_REQUEST
+ * Version 5.20 leave current rq on blkdev request list during I/O
+ * generalized ide_do_drive_cmd() for tape/cdrom driver use
+ * Version 5.21 fix nasty cdrom/tape bug (ide_preempt was messed up)
+ * Version 5.22 fix ide_xlate_1024() to work with/without drive->id
*
* Driver compile-time options are in ide.h
*
@@ -179,7 +187,6 @@
* - add ioctls to get/set interface timings on various interfaces
* - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
* - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- * - find someone to work on IDE *tape drive* support
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -246,10 +253,16 @@
return (t - i);
}
-void ide_set_recovery_timer (ide_hwif_t *hwif)
+static void set_recovery_timer (ide_hwif_t *hwif)
{
hwif->last_time = read_timer();
}
+#define SET_RECOVERY_TIMER(drive) set_recovery_timer (drive)
+
+#else
+
+#define SET_RECOVERY_TIMER(drive)
+
#endif /* DISK_RECOVERY_TIME */
/*
@@ -391,6 +404,10 @@
* Apparently, systems with multiple CMD640 chips may need something similar..
*
* This algorithm courtesy of malafoss@snakemail.hut.fi
+ *
+ * At least one user has reported that this code can confuse the floppy
+ * controller and/or driver -- perhaps this should be changed to use
+ * a read-modify-write sequence, so as not to disturb other bits in the reg?
*/
void ide_hwif_select (ide_hwif_t *hwif)
@@ -419,15 +436,17 @@
* timer is started to prevent us from waiting forever in case
* something goes wrong (see the timer_expiry() handler later on).
*/
-void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler)
+void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout)
{
ide_hwgroup_t *hwgroup = HWGROUP(drive);
#ifdef DEBUG
- if (hwgroup->handler != NULL)
- printk("%s: ide_set_handler: old handler not null\n", drive->name);
+ 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->timer.expires = jiffies + WAIT_CMD;
+ hwgroup->timer.expires = jiffies + timeout;
add_timer(&(hwgroup->timer));
}
@@ -468,8 +487,8 @@
if (!drive->present)
return 0;
- if (drive->media != disk)
- return 0x1fffff; /* cdrom */
+ if (drive->media != ide_disk)
+ return 0x7fffffff; /* cdrom or tape */
/* Determine capacity, and use LBA if the drive properly supports it */
if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) {
drive->select.b.lba = 1;
@@ -493,11 +512,15 @@
for (unit = 0; unit < gd->nr_real; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
#ifdef CONFIG_BLK_DEV_IDECD
- if (drive->present && drive->media == cdrom)
+ if (drive->present && drive->media == ide_cdrom)
ide_cdrom_setup(drive);
#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ if (drive->present && drive->media == ide_tape)
+ idetape_setup(drive);
+#endif /* CONFIG_BLK_DEV_IDETAPE */
drive->part[0].nr_sects = current_capacity(drive);
- if (!drive->present || drive->media != disk) {
+ if (!drive->present || drive->media != ide_disk) {
drive->part[0].start_sect = -1; /* skip partition check */
}
}
@@ -554,95 +577,54 @@
hwif->gd = gendisk_head = gd;
}
-static void unexpected_intr (int, ide_hwgroup_t *);
-/*
- * reset_ihandler() is a dummy interrupt handler which we install during
- * an ide interface reset operation. This prevents other devices in the
- * same hwgroup from being serviced while we play around with shared resources.
- * If it ever gets invoked, we call unexpected_intr(), which treats the event
- * the same as a timer_expiry().
- */
-static void reset_ihandler (ide_drive_t *drive)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- unexpected_intr (HWIF(drive)->irq, HWGROUP(drive));
- restore_flags(flags);
-}
-
-/*
- * start_reset_timer() sets up a timer event for 50ms in the future,
- * to poll for completion of an ide reset operation (no interrupt to help us).
- */
-static void start_reset_timer (ide_hwif_t *hwif)
-{
- ide_hwgroup_t *hwgroup = hwif->hwgroup;
+static void do_reset1 (ide_drive_t *, int); /* needed below */
- hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */
- hwgroup->handler = &reset_ihandler; /* dummy irq handler */
- hwgroup->timer.expires = jiffies + (HZ/20); /* polling interval */
- add_timer(&(hwgroup->timer));
-}
-
-#ifdef CONFIG_BLK_DEV_IDECD
+#ifdef CONFIG_BLK_DEV_IDEATAPI
/*
- * atapi_reset_handler() gets invoked to poll the interface for completion every 50ms
+ * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an atapi drive reset operation. If the drive has not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
- *
- * Returns 1 if waiting for another 50ms, returns 0 otherwise.
*/
-static int atapi_reset_handler (ide_hwgroup_t *hwgroup)
+static void atapi_reset_pollfunc (ide_drive_t *drive)
{
- ide_hwif_t *hwif = hwgroup->hwif;
- ide_drive_t *drive = hwgroup->drive;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
OUT_BYTE (drive->select.all, IDE_SELECT_REG);
udelay (10);
- if (!OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
- if (jiffies < hwgroup->reset_timeout) {
- start_reset_timer (hwif);
- return 1;
+ if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
+ printk("%s: ATAPI reset complete\n", drive->name);
+ } else {
+ if (jiffies < hwgroup->poll_timeout) {
+ ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
+ return; /* continue polling */
}
+ hwgroup->poll_timeout = 0; /* end of polling */
printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
- return ide_do_reset (drive); /* do it the old fashioned way */
+ do_reset1 (drive, 1); /* do it the old fashioned way */
}
- hwgroup->doing_atapi_reset = 0;
- hwgroup->handler = NULL; /* allow new requests to be processed */
- hwgroup->reset_timeout = 0; /* signal end of ide reset operation */
- printk("%s: ATAPI reset complete\n", drive->name);
- return 0;
+ hwgroup->poll_timeout = 0; /* done polling */
}
-#endif /* CONFIG_BLK_DEV_IDECD */
+#endif /* CONFIG_BLK_DEV_IDEATAPI */
/*
- * reset_handler() gets invoked to poll the interface for completion every 50ms
+ * reset_pollfunc() gets invoked to poll the interface for completion every 50ms
* during an ide reset operation. If the drives have not yet responded,
* and we have not yet hit our maximum waiting time, then the timer is restarted
* for another 50ms.
- *
- * Returns 1 if waiting for another 50ms, returns 0 otherwise.
*/
-static int reset_handler (ide_hwgroup_t *hwgroup)
+static void reset_pollfunc (ide_drive_t *drive)
{
- ide_hwif_t *hwif = hwgroup->hwif;
- ide_drive_t *drive = hwgroup->drive;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ ide_hwif_t *hwif = HWIF(drive);
byte tmp;
-#ifdef CONFIG_BLK_DEV_IDECD
- if (hwgroup->doing_atapi_reset)
- return atapi_reset_handler(hwgroup);
-#endif /* CONFIG_BLK_DEV_IDECD */
-
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
- if (jiffies < hwgroup->reset_timeout) {
- start_reset_timer (hwif);
- return 1;
+ if (jiffies < hwgroup->poll_timeout) {
+ ide_set_handler (drive, &reset_pollfunc, HZ/20);
+ return; /* continue polling */
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
} else {
@@ -669,13 +651,11 @@
printk("\n");
}
}
- hwgroup->handler = NULL; /* allow new requests to be processed */
- hwgroup->reset_timeout = 0; /* signal end of ide reset operation */
- return 0;
+ hwgroup->poll_timeout = 0; /* done polling */
}
/*
- * ide_do_reset() attempts to recover a confused drive by resetting it.
+ * do_reset1() attempts to recover a confused drive by resetting it.
* Unfortunately, resetting a disk drive actually resets all devices on
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
@@ -689,7 +669,7 @@
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
-int ide_do_reset (ide_drive_t *drive)
+static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
{
unsigned int unit;
unsigned long flags;
@@ -699,24 +679,22 @@
save_flags(flags);
cli(); /* Why ? */
-#ifdef CONFIG_BLK_DEV_IDECD
+#ifdef CONFIG_BLK_DEV_IDEATAPI
/* For an ATAPI device, first try an ATAPI SRST. */
- if (drive->media == cdrom) {
- if (!hwgroup->doing_atapi_reset) {
- hwgroup->doing_atapi_reset = 1;
+ if (drive->media != ide_disk) {
+ if (!do_not_try_atapi) {
if (!drive->keep_settings)
drive->unmask = 0;
OUT_BYTE (drive->select.all, IDE_SELECT_REG);
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
- hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
- start_reset_timer (hwif); /* begin periodic polling */
+ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
restore_flags (flags);
- return 1;
+ return;
}
}
- hwgroup->doing_atapi_reset = 0;
-#endif /* CONFIG_BLK_DEV_IDECD */
+#endif /* CONFIG_BLK_DEV_IDEATAPI */
/*
* First, reset any device state data we were maintaining
@@ -749,33 +727,45 @@
OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */
udelay(5); /* more than enough time */
OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */
- hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
- start_reset_timer (hwif); /* begin periodic polling */
+ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+ ide_set_handler (drive, &reset_pollfunc, HZ/20);
#endif /* OK_TO_RESET_CONTROLLER */
restore_flags (flags);
- return OK_TO_RESET_CONTROLLER; /* 1 = we are waiting, 0 = done */
}
/*
- * Clean up after success/failure of an explicit (ioctl) drive cmd
+ * ide_do_reset() is the entry point to the drive/interface reset code.
+ */
+void ide_do_reset (ide_drive_t *drive)
+{
+ do_reset1 (drive, 0);
+}
+
+/*
+ * Clean up after success/failure of an explicit drive cmd
*/
-static void end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
+void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err)
{
unsigned long flags;
struct request *rq = HWGROUP(drive)->rq;
- byte *args = (byte *) rq->buffer;
- rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
- if (args) {
- args[0] = stat;
- args[1] = err;
- args[2] = IN_BYTE(IDE_NSECTOR_REG);
+ if (rq->cmd == IDE_DRIVE_CMD) {
+ byte *args = (byte *) rq->buffer;
+ rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+ if (args) {
+ args[0] = stat;
+ args[1] = err;
+ args[2] = IN_BYTE(IDE_NSECTOR_REG);
+ }
}
save_flags(flags);
cli();
- up(rq->sem);
+ blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next;
HWGROUP(drive)->rq = NULL;
+ rq->rq_status = RQ_INACTIVE;
+ if (rq->sem != NULL)
+ up(rq->sem);
restore_flags(flags);
}
@@ -791,7 +781,7 @@
sti();
printk("%s: %s: status=0x%02x", drive->name, msg, stat);
#if FANCY_STATUS_DUMPS
- if (drive->media == disk) {
+ if (drive->media == ide_disk) {
printk(" { ");
if (stat & BUSY_STAT)
printk("Busy ");
@@ -812,7 +802,7 @@
err = GET_ERR();
printk("%s: %s: error=0x%02x", drive->name, msg, err);
#if FANCY_STATUS_DUMPS
- if (drive->media == disk) {
+ if (drive->media == ide_disk) {
printk(" { ");
if (err & BBD_ERR) printk("BadSector ");
if (err & ECC_ERR) printk("UncorrectableError ");
@@ -868,28 +858,25 @@
/*
* ide_error() takes action based on the error returned by the controller.
- *
- * Returns 1 if an ide reset operation has been initiated, in which case
- * the caller MUST simply return from the driver (through however many levels).
- * Returns 0 otherwise.
*/
-int ide_error (ide_drive_t *drive, const char *msg, byte stat)
+void ide_error (ide_drive_t *drive, const char *msg, byte stat)
{
struct request *rq;
byte err;
err = ide_dump_status(drive, msg, stat);
if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL)
- return 0;
- if (rq->cmd == IDE_DRIVE_CMD) { /* never retry an explicit DRIVE_CMD */
- end_drive_cmd(drive, stat, err);
- return 0;
+ return;
+ if (rq->cmd != READ && rq->cmd != WRITE) { /* retry only "normal" i/o */
+ rq->errors = 1;
+ ide_end_drive_cmd(drive, stat, err);
+ return;
}
if (stat & BUSY_STAT) { /* other bits are useless when BUSY */
rq->errors |= ERROR_RESET;
} else {
- if (drive->media == disk && (stat & ERR_STAT)) {
- /* err has different meaning on cdrom */
+ if (drive->media == ide_disk && (stat & ERR_STAT)) {
+ /* err has different meaning on cdrom and tape */
if (err & BBD_ERR) /* retries won't help this! */
rq->errors = ERROR_MAX;
else if (err & TRK0_ERR) /* help it find track zero */
@@ -906,7 +893,7 @@
drive->using_dma = 0;
printk("%s: DMA disabled\n", drive->name);
--rq->errors;
- return 0;
+ return;
}
#endif /* CONFIG_BLK_DEV_TRITON */
if (rq->errors >= ERROR_MAX)
@@ -914,12 +901,12 @@
else {
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
++rq->errors;
- return ide_do_reset(drive);
+ ide_do_reset(drive);
+ return;
} else if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
drive->special.b.recalibrate = 1;
++rq->errors;
}
- return 0;
}
/*
@@ -933,9 +920,7 @@
struct request *rq;
if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
- sti();
- if (!ide_error(drive, "read_intr", stat))
- IDE_DO_REQUEST;
+ ide_error(drive, "read_intr", stat);
return;
}
msect = drive->mult_count;
@@ -962,10 +947,8 @@
if (i > 0) {
if (msect)
goto read_next;
- ide_set_handler (drive, &read_intr);
- return;
+ ide_set_handler (drive, &read_intr, WAIT_CMD);
}
- IDE_DO_REQUEST;
}
/*
@@ -975,7 +958,8 @@
{
byte stat;
int i;
- struct request *rq = HWGROUP(drive)->rq;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ struct request *rq = hwgroup->rq;
if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
#ifdef DEBUG
@@ -990,19 +974,15 @@
i = --rq->nr_sectors;
--rq->current_nr_sectors;
if (rq->current_nr_sectors <= 0)
- ide_end_request(1, HWGROUP(drive));
+ ide_end_request(1, hwgroup);
if (i > 0) {
ide_output_data (drive, rq->buffer, SECTOR_WORDS);
- ide_set_handler (drive, &write_intr);
- return;
+ ide_set_handler (drive, &write_intr, WAIT_CMD);
}
- IDE_DO_REQUEST;
return;
}
}
- sti();
- if (!ide_error(drive, "write_intr", stat))
- IDE_DO_REQUEST;
+ ide_error(drive, "write_intr", stat);
}
/*
@@ -1049,30 +1029,28 @@
{
byte stat;
int i;
- struct request *rq = &HWGROUP(drive)->wrq;
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
+ struct request *rq = &hwgroup->wrq;
if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
if (stat & DRQ_STAT) {
if (rq->nr_sectors) {
multwrite(drive);
- ide_set_handler (drive, &multwrite_intr);
+ ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
return;
}
} else {
if (!rq->nr_sectors) { /* all done? */
- rq = HWGROUP(drive)->rq;
+ rq = hwgroup->rq;
for (i = rq->nr_sectors; i > 0;){
i -= rq->current_nr_sectors;
- ide_end_request(1, HWGROUP(drive));
+ ide_end_request(1, hwgroup);
}
- IDE_DO_REQUEST;
return;
}
}
}
- sti();
- if (!ide_error(drive, "multwrite_intr", stat))
- IDE_DO_REQUEST;
+ ide_error(drive, "multwrite_intr", stat);
}
/*
@@ -1081,7 +1059,7 @@
*/
static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
- ide_set_handler (drive, handler);
+ ide_set_handler (drive, handler, WAIT_CMD);
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
OUT_BYTE(nsect,IDE_NSECTOR_REG);
OUT_BYTE(cmd,IDE_COMMAND_REG);
@@ -1102,7 +1080,6 @@
drive->special.b.recalibrate = 1;
(void) ide_dump_status(drive, "set_multmode", stat);
}
- IDE_DO_REQUEST;
}
/*
@@ -1114,9 +1091,7 @@
sti();
if (!OK_STAT(stat,READY_STAT,BAD_STAT))
- if (ide_error(drive, "set_geometry_intr", stat))
- return;
- IDE_DO_REQUEST;
+ ide_error(drive, "set_geometry_intr", stat);
}
/*
@@ -1128,9 +1103,7 @@
sti();
if (!OK_STAT(stat,READY_STAT,BAD_STAT))
- if (ide_error(drive, "recal_intr", stat))
- return;
- IDE_DO_REQUEST;
+ ide_error(drive, "recal_intr", stat);
}
/*
@@ -1142,10 +1115,9 @@
sti();
if (OK_STAT(stat,READY_STAT,BAD_STAT))
- end_drive_cmd (drive, stat, GET_ERR());
- else if (ide_error(drive, "drive_cmd", stat)) /* calls end_drive_cmd */
- return;
- IDE_DO_REQUEST;
+ ide_end_drive_cmd (drive, stat, GET_ERR());
+ else
+ ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
}
/*
@@ -1161,7 +1133,7 @@
#endif
if (s->b.set_geometry) {
s->b.set_geometry = 0;
- if (drive->media == disk) {
+ if (drive->media == ide_disk) {
OUT_BYTE(drive->sect,IDE_SECTOR_REG);
OUT_BYTE(drive->cyl,IDE_LCYL_REG);
OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);
@@ -1170,12 +1142,12 @@
}
} else if (s->b.recalibrate) {
s->b.recalibrate = 0;
- if (drive->media == disk) {
+ if (drive->media == ide_disk) {
ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);
}
} else if (s->b.set_multmode) {
s->b.set_multmode = 0;
- if (drive->media == disk) {
+ if (drive->media == ide_disk) {
if (drive->id && drive->mult_req > drive->id->max_multsect)
drive->mult_req = drive->id->max_multsect;
ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);
@@ -1191,23 +1163,24 @@
* 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()
+ * cases return 1 after invoking ide_error() -- caller should just return.
*
* 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 WAIT_WORSTCASE is achieved, before timing out.
+ * until timeout is achieved, before timing out.
*/
int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
{
byte stat;
unsigned long flags;
+
test:
udelay(1); /* spec allows drive 400ns to change "BUSY" */
if (OK_STAT((stat = GET_STAT()), good, bad))
return 0; /* fast exit for most frequent case */
if (!(stat & BUSY_STAT)) {
- (void) ide_error(drive, "status error", stat);
+ ide_error(drive, "status error", stat);
return 1;
}
@@ -1222,7 +1195,7 @@
} while (jiffies <= timeout);
restore_flags(flags);
- (void) ide_error(drive, "status timeout", GET_STAT());
+ ide_error(drive, "status timeout", GET_STAT());
return 1;
}
@@ -1268,7 +1241,7 @@
if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
return;
#endif /* CONFIG_BLK_DEV_TRITON */
- ide_set_handler(drive, &read_intr);
+ ide_set_handler(drive, &read_intr, WAIT_CMD);
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+IDE_COMMAND_OFFSET);
return;
}
@@ -1287,10 +1260,10 @@
cli();
if (drive->mult_count) {
HWGROUP(drive)->wrq = *rq; /* scratchpad */
- ide_set_handler (drive, &multwrite_intr);
+ ide_set_handler (drive, &multwrite_intr, WAIT_CMD);
multwrite(drive);
} else {
- ide_set_handler (drive, &write_intr);
+ ide_set_handler (drive, &write_intr, WAIT_CMD);
ide_output_data(drive, rq->buffer, SECTOR_WORDS);
}
return;
@@ -1311,7 +1284,7 @@
#ifdef DEBUG
printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
- end_drive_cmd(drive, GET_STAT(), GET_ERR());
+ ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
return;
}
}
@@ -1330,7 +1303,7 @@
sti();
#ifdef DEBUG
- printk("%s: ide_do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
+ printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
#endif
minor = MINOR(rq->rq_dev);
unit = minor >> PARTN_BITS;
@@ -1372,17 +1345,25 @@
if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk("%s: drive not ready for command\n", drive->name);
return;
-
}
if (!drive->special.all) {
-#ifdef CONFIG_BLK_DEV_IDECD
+#ifdef CONFIG_BLK_DEV_IDEATAPI
switch (drive->media) {
- case disk:
+ case ide_disk:
do_rw_disk (drive, rq, block);
return;
- case cdrom:
+#ifdef CONFIG_BLK_DEV_IDECD
+ case ide_cdrom:
ide_do_rw_cdrom (drive, block);
return;
+#endif /* CONFIG_BLK_DEV_IDECD */
+
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ case ide_tape:
+ idetape_do_request (drive, rq, block);
+ return;
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+
default:
printk("%s: media type %d not supported\n",
drive->name, drive->media);
@@ -1391,7 +1372,7 @@
#else
do_rw_disk (drive, rq, block); /* simpler and faster */
return;
-#endif;
+#endif /* CONFIG_BLK_DEV_IDEATAPI */;
}
do_special(drive);
return;
@@ -1425,16 +1406,14 @@
ide_hwif_t *hwif = hwgroup->hwif;
struct request *rq;
if ((rq = hwgroup->rq) == NULL) {
- hwgroup->drive = NULL; /* paranoia */
do {
rq = blk_dev[hwif->major].current_request;
if (rq != NULL && rq->rq_status != RQ_INACTIVE)
goto got_rq;
} while ((hwif = hwif->next) != hwgroup->hwif);
return; /* no work left for this hwgroup */
- got_rq:
- blk_dev[hwif->major].current_request = rq->next;
}
+ got_rq:
do_request(hwgroup->hwif = hwif, hwgroup->rq = rq);
cli();
} while (hwgroup->handler == NULL);
@@ -1495,19 +1474,21 @@
save_flags(flags);
cli();
- if (hwgroup->reset_timeout != 0) { /* ide reset in progress? */
- if (!reset_handler(hwgroup))
- do_hwgroup_request (hwgroup);
+ if (hwgroup->poll_timeout != 0) { /* polling in progress? */
+ ide_handler_t *handler = hwgroup->handler;
+ hwgroup->handler = NULL;
+ handler(drive);
} else if (hwgroup->handler == NULL) { /* not waiting for anything? */
sti(); /* drive must have responded just as the timer expired */
printk("%s: marginal timeout\n", drive->name);
- } else { /* drive not responding */
- hwgroup->handler = NULL;
+ } else {
+ hwgroup->handler = NULL; /* abort the operation */
if (hwgroup->hwif->dmaproc)
(void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
- if (!ide_error(drive, "irq timeout", GET_STAT()))
- do_hwgroup_request (hwgroup);
+ ide_error(drive, "irq timeout", GET_STAT());
}
+ if (hwgroup->handler == NULL)
+ do_hwgroup_request (hwgroup);
restore_flags(flags);
}
@@ -1541,15 +1522,6 @@
ide_hwif_t *hwif = hwgroup->hwif;
/*
- * check for ide reset in progress
- */
- if (hwgroup->reset_timeout != 0) {
- if (!reset_handler(hwgroup))
- do_hwgroup_request (hwgroup);
- return;
- }
-
- /*
* handle the unexpected interrupt
*/
do {
@@ -1586,6 +1558,11 @@
if (drive->unmask)
sti();
handler(drive);
+ cli(); /* this is necessary, as next rq may be different irq */
+ if (hwgroup->handler == NULL) {
+ SET_RECOVERY_TIMER(HWIF(drive));
+ ide_do_request(hwgroup);
+ }
} else {
unexpected_intr(irq, hwgroup);
}
@@ -1621,49 +1598,83 @@
}
/*
- * This function issues a specific IDE drive command onto the
- * tail of the request queue, and waits for it to be completed.
- * If arg is NULL, it goes through all the motions,
- * but without actually sending a command to the drive.
+ * This function is intended to be used prior to invoking ide_do_drive_cmd().
*/
-int ide_do_drive_cmd(kdev_t rdev, char *args)
+void ide_init_drive_cmd (struct request *rq)
+{
+ rq->buffer = NULL;
+ rq->cmd = IDE_DRIVE_CMD;
+ rq->sector = 0;
+ rq->nr_sectors = 0;
+ rq->current_nr_sectors = 0;
+ rq->sem = NULL;
+ rq->bh = NULL;
+ rq->bhtail = NULL;
+ rq->next = NULL;
+
+#if 0 /* these are done each time through ide_do_drive_cmd() */
+ rq->errors = 0;
+ rq->rq_status = RQ_ACTIVE;
+ rq->rq_dev = ????;
+#endif
+}
+
+/*
+ * This function issues a special IDE device request
+ * onto the request queue.
+ *
+ * If action is ide_wait, then then rq is queued at the end of
+ * the request queue, and the function sleeps until it has been
+ * processed. This is for use when invoked from an ioctl handler.
+ *
+ * If action is ide_preempt, then the rq is queued at the head of
+ * the request queue, displacing the currently-being-processed
+ * request and this function returns immediately without waiting
+ * for the new rq to be completed. This is VERY DANGEROUS, and is
+ * intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_next, then the rq is queued immediately after
+ * the currently-being-processed-request (if any), and the function
+ * returns without waiting for the new rq to be completed. As above,
+ * This is VERY DANGEROUS, and is intended for careful use by the
+ * ATAPI tape/cdrom driver code.
+ */
+int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
{
unsigned long flags;
- unsigned int major = MAJOR(rdev);
- struct request rq, *cur_rq;
- struct blk_dev_struct *bdev;
+ unsigned int major = HWIF(drive)->major;
+ struct request *cur_rq;
+ struct blk_dev_struct *bdev = &blk_dev[major];
struct semaphore sem = MUTEX_LOCKED;
- /* build up a special request, and add it to the queue */
- rq.buffer = args;
- rq.cmd = IDE_DRIVE_CMD;
- rq.errors = 0;
- rq.sector = 0;
- rq.nr_sectors = 0;
- rq.current_nr_sectors = 0;
- rq.sem = &sem;
- rq.bh = NULL;
- rq.bhtail = NULL;
- rq.next = NULL;
- rq.rq_status = RQ_ACTIVE;
- rq.rq_dev = rdev;
- bdev = &blk_dev[major];
+ rq->errors = 0;
+ rq->rq_status = RQ_ACTIVE;
+ rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+ if (action == ide_wait)
+ rq->sem = &sem;
save_flags(flags);
cli();
cur_rq = bdev->current_request;
- if (cur_rq == NULL) { /* empty request list? */
- bdev->current_request = &rq; /* service ours immediately */
- bdev->request_fn();
+
+ if (cur_rq == NULL || action == ide_preempt) {
+ rq->next = cur_rq;
+ bdev->current_request = rq;
+ HWGROUP(drive)->rq = NULL;
+ if (action != ide_preempt)
+ bdev->request_fn();
} else {
- while (cur_rq->next != NULL) /* find end of request list */
- cur_rq = cur_rq->next;
- cur_rq->next = &rq; /* add rq to the end */
+ if (action == ide_wait) {
+ while (cur_rq->next != NULL) /* find end of list */
+ cur_rq = cur_rq->next;
+ }
+ rq->next = cur_rq->next;
+ cur_rq->next = rq;
}
-
- down(&sem); /* wait for it to be serviced */
+ if (action == ide_wait)
+ down(&sem); /* wait for it to be serviced */
restore_flags(flags);
- return rq.errors ? -EIO : 0; /* return -EIO if errors */
+ return rq->errors ? -EIO : 0; /* return -EIO if errors */
}
static int ide_open(struct inode * inode, struct file * filp)
@@ -1680,13 +1691,20 @@
drive->usage++;
restore_flags(flags);
#ifdef CONFIG_BLK_DEV_IDECD
- if (drive->media == cdrom)
+ if (drive->media == ide_cdrom)
return ide_cdrom_open (inode, filp, drive);
#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ if (drive->media == ide_tape)
+ return idetape_blkdev_open (inode, filp, drive);
+#endif /* CONFIG_BLK_DEV_IDETAPE */
if (drive->removeable) {
byte door_lock[] = {WIN_DOORLOCK,0,0,0};
+ struct request rq;
check_disk_change(inode->i_rdev);
- ide_do_drive_cmd(inode->i_rdev, door_lock);
+ ide_init_drive_cmd (&rq);
+ rq.buffer = door_lock;
+ return ide_do_drive_cmd(drive, &rq, ide_wait);
}
return 0;
}
@@ -1703,14 +1721,24 @@
sync_dev(inode->i_rdev);
drive->usage--;
#ifdef CONFIG_BLK_DEV_IDECD
- if (drive->media == cdrom)
+ if (drive->media == ide_cdrom) {
ide_cdrom_release (inode, file, drive);
- else
+ return;
+ }
#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ if (drive->media == ide_tape) {
+ idetape_blkdev_release (inode, file, drive);
+ return;
+ }
+#endif /* CONFIG_BLK_DEV_IDETAPE */
if (drive->removeable) {
byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0};
+ struct request rq;
invalidate_buffers(inode->i_rdev);
- ide_do_drive_cmd(inode->i_rdev, door_unlock);
+ ide_init_drive_cmd (&rq);
+ rq.buffer = door_unlock;
+ (void) ide_do_drive_cmd(drive, &rq, ide_wait);
}
}
}
@@ -1755,7 +1783,7 @@
};
drive->part[0].nr_sects = current_capacity(drive);
- if (drive->media == disk)
+ if (drive->media == ide_disk)
resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);
drive->busy = 0;
@@ -1782,14 +1810,16 @@
int err;
ide_drive_t *drive;
unsigned long flags;
+ struct request rq;
+ ide_init_drive_cmd (&rq);
if (!inode || !(inode->i_rdev))
return -EINVAL;
if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENODEV;
switch (cmd) {
case HDIO_GETGEO:
- if (!loc || drive->media != disk) return -EINVAL;
+ if (!loc || drive->media != ide_disk) return -EINVAL;
err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
if (err) return err;
put_user(drive->bios_head, (byte *) &loc->heads);
@@ -1848,7 +1878,7 @@
return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
case HDIO_SET_DMA:
- if (drive->media != disk)
+ if (drive->media != ide_disk)
return -EPERM;
if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
return -EPERM;
@@ -1914,7 +1944,7 @@
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
restore_flags(flags);
- ide_do_drive_cmd (inode->i_rdev, NULL);
+ (void) ide_do_drive_cmd (drive, &rq, ide_wait);
return (drive->mult_count == arg) ? 0 : -EIO;
case HDIO_DRIVE_CMD:
@@ -1922,13 +1952,14 @@
unsigned long args;
if (NULL == (long *) arg)
- err = ide_do_drive_cmd(inode->i_rdev,NULL);
+ err = ide_do_drive_cmd(drive, &rq, ide_wait);
else {
if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long))))
{
args = get_user((long *)arg);
if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) {
- err = ide_do_drive_cmd(inode->i_rdev,(char *)&args);
+ rq.buffer = (char *) &args;
+ err = ide_do_drive_cmd(drive, &rq, ide_wait);
put_user(args,(long *)arg);
}
}
@@ -1940,9 +1971,13 @@
default:
#ifdef CONFIG_BLK_DEV_IDECD
- if (drive->media == cdrom)
+ if (drive->media == ide_cdrom)
return ide_cdrom_ioctl(drive, inode, file, cmd, arg);
#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ if (drive->media == ide_tape)
+ return idetape_blkdev_ioctl(drive, inode, file, cmd, arg);
+#endif /* CONFIG_BLK_DEV_IDETAPE */
return -EPERM;
}
}
@@ -1954,7 +1989,7 @@
if ((drive = get_info_ptr(i_rdev)) == NULL)
return -ENODEV;
#ifdef CONFIG_BLK_DEV_IDECD
- if (drive->media == cdrom)
+ if (drive->media == ide_cdrom)
return ide_cdrom_check_media_change (drive);
#endif /* CONFIG_BLK_DEV_IDECD */
if (drive->removeable) /* for disks */
@@ -2027,22 +2062,45 @@
/*
* Check for an ATAPI device
*/
+
if (cmd == WIN_PIDENTIFY) {
+ byte type = (id->config >> 8) & 0x1f;
+ printk("%s: %s, ATAPI ", drive->name, id->model);
+ switch (type) {
+ case 0: /* Early cdrom models used zero */
+ case 5:
#ifdef CONFIG_BLK_DEV_IDECD
- byte type = (id->config >> 8) & 0x0f;
-#endif /* CONFIG_BLK_DEV_IDECD */
- printk("%s: %s, ATAPI, ", drive->name, id->model);
- drive->media = cdrom;
-#ifdef CONFIG_BLK_DEV_IDECD
- if (type == 0 || type == 5)
- printk("CDROM drive\n");
- else
- printk("UNKNOWN device\n");
- drive->present = 1;
- drive->removeable = 1;
+ printk ("CDROM drive\n");
+ drive->media = ide_cdrom;
+ drive->present = 1;
+ drive->removeable = 1;
+ return;
#else
- printk("not supported by this kernel\n");
-#endif /* CONFIG_BLK_DEV_IDECD */
+ printk ("CDROM ");
+ break;
+#endif /* CONFIG_BLK_DEV_IDECD */
+ case 1:
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ printk ("TAPE drive\n");
+ if (idetape_identify_device (drive,id)) {
+ drive->media = ide_tape;
+ drive->present = 1;
+ drive->removeable = 1;
+ }
+ else {
+ drive->present = 0;
+ printk ("ide-tape: The tape is not supported by this version of the driver\n");
+ }
+ return;
+#else
+ printk ("TAPE ");
+ break;
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+ default:
+ printk("Type %d - Unknown device\n", type);
+ return;
+ }
+ printk("- not supported by this kernel\n");
return;
}
@@ -2052,7 +2110,7 @@
drive->removeable = 1;
}
- drive->media = disk;
+ drive->media = ide_disk;
/* Extract geometry if we did not already have one for the drive */
if (!drive->present) {
drive->present = 1;
@@ -2211,15 +2269,15 @@
static int do_probe (ide_drive_t *drive, byte cmd)
{
int rc;
-#ifdef CONFIG_BLK_DEV_IDECD
+#ifdef CONFIG_BLK_DEV_IDEATAPI
if (drive->present) { /* avoid waiting for inappropriate probes */
- if ((drive->media == cdrom) && (cmd == WIN_IDENTIFY))
+ if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
return 4;
}
-#endif /* CONFIG_BLK_DEV_IDECD */
+#endif /* CONFIG_BLK_DEV_IDEATAPI */
#ifdef DEBUG
- printk("probing for %s: present=%d, type=%s, probetype=%s\n",
- drive->name, drive->present, drive->media ? "cdrom":"disk",
+ printk("probing for %s: present=%d, media=%d, probetype=%s\n",
+ drive->name, drive->present, drive->media,
(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
#endif
#if SUPPORT_HT6560B
@@ -2263,19 +2321,19 @@
if (drive->noprobe) /* skip probing? */
return drive->present;
if (do_probe(drive, WIN_IDENTIFY) >= 2) { /* if !(success||timed-out) */
-#ifdef CONFIG_BLK_DEV_IDECD
+#ifdef CONFIG_BLK_DEV_IDEATAPI
(void) do_probe(drive, WIN_PIDENTIFY); /* look for ATAPI device */
-#endif /* CONFIG_BLK_DEV_IDECD */
+#endif /* CONFIG_BLK_DEV_IDEATAPI */
}
if (!drive->present)
return 0; /* drive not found */
if (drive->id == NULL) { /* identification failed? */
- if (drive->media == disk) {
+ if (drive->media == ide_disk) {
printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
drive->name, drive->cyl, drive->head, drive->sect);
}
#ifdef CONFIG_BLK_DEV_IDECD
- else if (drive->media == cdrom) {
+ else if (drive->media == ide_cdrom) {
printk("%s: ATAPI cdrom (?)\n", drive->name);
}
#endif /* CONFIG_BLK_DEV_IDECD */
@@ -2284,7 +2342,7 @@
return 1; /* drive was found */
}
}
- if (drive->media == disk && !drive->select.b.lba) {
+ if (drive->media == ide_disk && !drive->select.b.lba) {
if (!drive->head || drive->head > 16) {
printk("%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
drive->name, drive->head);
@@ -2568,14 +2626,14 @@
goto done;
case -3: /* "cdrom" */
drive->present = 1;
- drive->media = cdrom;
+ drive->media = ide_cdrom;
hwif->noprobe = 0;
goto done;
case -4: /* "serialize" */
printk(" -- USE \"ide%c=serialize\" INSTEAD", '0'+hw);
goto do_serialize;
case 3: /* cyl,head,sect */
- drive->media = disk;
+ drive->media = ide_disk;
drive->cyl = drive->bios_cyl = vals[0];
drive->head = drive->bios_head = vals[1];
drive->sect = drive->bios_sect = vals[2];
@@ -2679,12 +2737,17 @@
const byte *heads = head_vals;
unsigned long tracks;
- if ((drive = get_info_ptr(i_rdev)) == NULL || drive->id == NULL)
+ if ((drive = get_info_ptr(i_rdev)) == NULL)
return 0;
- drive->cyl = drive->bios_cyl = drive->id->cyls;
- drive->head = drive->bios_head = drive->id->heads;
- drive->sect = drive->bios_sect = drive->id->sectors;
+ if (drive->id) {
+ drive->bios_cyl = drive->id->cyls;
+ drive->bios_head = drive->id->heads;
+ drive->bios_sect = drive->id->sectors;
+ }
+ drive->cyl = drive->bios_cyl;
+ drive->head = drive->bios_head;
+ drive->sect = drive->bios_sect;
drive->special.b.set_geometry = 1;
tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
@@ -2801,11 +2864,8 @@
hwgroup->hwif = hwif->next = hwif;
hwgroup->rq = NULL;
hwgroup->handler = NULL;
- hwgroup->drive = NULL;
- hwgroup->reset_timeout = 0;
-#ifdef CONFIG_BLK_DEV_IDECD
- hwgroup->doing_atapi_reset = 0;
-#endif /* CONFIG_BLK_DEV_IDECD */
+ hwgroup->drive = &hwif->drives[0];
+ hwgroup->poll_timeout = 0;
init_timer(&hwgroup->timer);
hwgroup->timer.function = &timer_expiry;
hwgroup->timer.data = (unsigned long) hwgroup;
@@ -3002,5 +3062,10 @@
hwif->present = 1; /* success */
}
}
+
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ idetape_register_chrdev(); /* Register character device interface to the ide tape */
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this