patch-1.3.21 linux/drivers/block/ide.c
Next file: linux/drivers/block/ide.h
Previous file: linux/drivers/block/ide-cd.c
Back to the patch index
Back to the overall index
- Lines: 876
- Date:
Mon Aug 28 09:19:32 1995
- Orig file:
v1.3.20/linux/drivers/block/ide.c
- Orig date:
Tue Aug 15 20:39:01 1995
diff -u --recursive --new-file v1.3.20/linux/drivers/block/ide.c linux/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 5.03 Aug 13, 1995
+ * linux/drivers/block/ide.c Version 5.10 Aug 26, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
@@ -115,12 +115,20 @@
* Version 5.03 tune-ups, comments, remove "busy wait" from drive resets
* removed PROBE_FOR_IRQS option -- no longer needed
* OOOPS! fixed "bad access" bug for 2nd drive on an i/f
+ * Version 5.04 changed "ira %d" to "irq %d" in DEBUG message
+ * added more comments, cleaned up unexpected_intr()
+ * OOOPS! fixed null pointer problem in ide reset code
+ * added autodetect for Triton chipset -- no effect yet
+ * Version 5.05 OOOPS! fixed bug in revalidate_disk()
+ * OOOPS! fixed bug in ide_do_request()
+ * added ATAPI reset sequence for cdroms
+ * Version 5.10 added Bus-Mastered DMA support for Triton Chipset
+ * some (mostly) cosmetic changes
*
* Driver compile-time options are in ide.h
*
* To do, in likely order of completion:
* - add in several updates from my email collection (soon folks!)
- * - add full support for Intel Triton chipset, including bus-mastered DMA
* - improved CMD support: handing this off to someone else
* - find someone to work on IDE *tape drive* support
*/
@@ -142,6 +150,10 @@
#include <asm/byteorder.h>
#include <asm/irq.h>
+#ifdef CONFIG_PCI
+#include <linux/bios32.h>
+#endif /* CONFIG_PCI */
+
#include "ide.h"
static ide_hwif_t ide_hwifs[MAX_HWIFS]; /* hwif info */
@@ -196,50 +208,46 @@
* ide_drive_t structs as needed, rather than always consuming memory
* for the max possible number (MAX_HWIFS * MAX_DRIVES) of them.
*/
+#define MAGIC_COOKIE 0x12345678
static void init_ide_data (void)
{
+ byte *p;
unsigned int h, unit;
- static unsigned long magic_cookie = 0x12345678;
+ static unsigned long magic_cookie = MAGIC_COOKIE;
- if (magic_cookie != 0x12345678)
+ if (magic_cookie != MAGIC_COOKIE)
return; /* already initialized */
magic_cookie = 0;
for (h = 0; h < 16; ++h)
irq_to_hwgroup[h] = NULL;
+ /* bulk initialize hwif & drive info with zeros */
+ p = ((byte *) ide_hwifs) + sizeof(ide_hwifs);
+ do {
+ *--p = 0;
+ } while (p > (byte *) ide_hwifs);
+
for (h = 0; h < MAX_HWIFS; ++h) {
ide_hwif_t *hwif = &ide_hwifs[h];
+ /* fill in any non-zero initial values */
hwif->noprobe = (h > 1);
- hwif->hwgroup = NULL;
hwif->io_base = default_io_base[h];
hwif->ctl_port = hwif->io_base ? hwif->io_base + 0x206 : 0x000;
#ifdef CONFIG_BLK_DEV_HD
if (hwif->io_base == HD_DATA)
hwif->noprobe = 1; /* may be overriden by ide_setup() */
#endif /* CONFIG_BLK_DEV_HD */
- hwif->gd = NULL;
- hwif->irq = 0; /* default_irqs[h] used when probe fails */
hwif->major = ide_hwif_to_major[h];
hwif->name[0] = 'i';
hwif->name[1] = 'd';
hwif->name[2] = 'e';
hwif->name[3] = '0' + h;
- hwif->name[4] = '\0';
- hwif->present = 0;
- hwif->next = NULL;
- hwif->reset_timeout = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
- /* bulk initialize drive info with zeros */
- byte *p = ((byte *) drive) + sizeof(ide_drive_t);
- do {
- *--p = 0;
- } while (p > (byte *) drive);
-
/* fill in any non-zero initial values */
drive->select.all = (unit<<4)|0xa0;
drive->hwif = hwif;
@@ -257,7 +265,13 @@
#ifdef __i386__
#define VLB_SYNC 1
-
+/*
+ * Some localbus EIDE interfaces require a special access sequence
+ * when using 32-bit I/O instructions to transfer data. We call this
+ * the "vlb_sync" sequence, which consists of three successive reads
+ * of the sector count register location, with interrupts disabled
+ * to ensure that the reads all happen together.
+ */
static inline void do_vlb_sync (unsigned short port) {
unsigned int _v;
__asm__ __volatile__ (
@@ -404,16 +418,30 @@
}
/*
- * ide_alloc(): memory allocation for using during driver initialization.
- */
-static unsigned long init_mem_start = 0uL; /* used by init routines */
-
-static inline void *ide_alloc (unsigned long bytecount)
-{
- unsigned long p = init_mem_start;
- if (!p) panic("ide: ide_alloc() not valid now\n");
- init_mem_start += (bytecount + 3uL) & ~3uL;
- return (void *) p;
+ * ide_alloc(): memory allocation for use *only* during driver initialization.
+ * If "within_area" is non-zero, the memory will be allocated such that
+ * it lies entirely within a "within_area" sized area (eg. 4096). This is
+ * needed for DMA stuff. "within_area" must be a power of two (not validated).
+ * All allocations are longword aligned.
+ */
+static unsigned long ide_mem_start = 0uL; /* used by ide_alloc() */
+
+void *ide_alloc (unsigned long bytecount, unsigned long within_area)
+{
+ const unsigned long longsize_m1 = (sizeof(long) - 1);
+ void *p;
+
+ if (!ide_mem_start)
+ panic("ide: ide_alloc() not valid now\n");
+ ide_mem_start = (ide_mem_start + longsize_m1) & ~longsize_m1;
+ if (within_area) {
+ unsigned long fraction = within_area - (ide_mem_start & (within_area - 1));
+ if (fraction < bytecount)
+ ide_mem_start += fraction; /* realign to a new page */
+ }
+ p = (void *) ide_mem_start;
+ ide_mem_start += (bytecount + longsize_m1) & ~longsize_m1;
+ return p;
}
/*
@@ -434,10 +462,10 @@
break;
}
minors = units * (1<<PARTN_BITS);
- gd = ide_alloc(sizeof(struct gendisk));
- gd->sizes = ide_alloc(minors * sizeof(int));
- gd->part = ide_alloc(minors * sizeof(struct hd_struct));
- bs = ide_alloc(minors*sizeof(int));
+ gd = ide_alloc (sizeof(struct gendisk), 0);
+ gd->sizes = ide_alloc (minors * sizeof(int), 0);
+ gd->part = ide_alloc (minors * sizeof(struct hd_struct), 0);
+ bs = ide_alloc (minors*sizeof(int), 0);
/* cdroms and msdos f/s are examples of non-1024 blocksizes */
blksize_size[hwif->major] = bs;
@@ -470,7 +498,12 @@
*/
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);
}
/*
@@ -481,15 +514,49 @@
{
ide_hwgroup_t *hwgroup = hwif->hwgroup;
- hwif->reset_timeout = jiffies + WAIT_WORSTCASE; /* max waiting time */
+ 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
+/*
+ * atapi_reset_handler() 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)
+{
+ ide_hwif_t *hwif = hwgroup->hwif;
+ ide_drive_t *drive = 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;
+ }
+ printk("%s: ATAPI reset timed-out, status=0x%02x\n", drive->name, stat);
+ return ide_do_reset (drive); /* 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;
+}
+#endif /* CONFIG_BLK_DEV_IDECD */
+
/*
* reset_handler() gets invoked to poll the interface for completion every 50ms
- * during an ide reset operation. If the drives have not not responded,
+ * 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.
*
@@ -501,8 +568,13 @@
ide_drive_t *drive = hwgroup->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 < hwif->reset_timeout) {
+ if (jiffies < hwgroup->reset_timeout) {
start_reset_timer (hwif);
return 1;
}
@@ -532,7 +604,7 @@
}
}
hwgroup->handler = NULL; /* allow new requests to be processed */
- hwif->reset_timeout = 0; /* signal end of ide reset operation */
+ hwgroup->reset_timeout = 0; /* signal end of ide reset operation */
return 0;
}
@@ -542,9 +614,8 @@
* the same interface, so it can really be thought of as resetting the
* interface rather than resetting the drive.
*
- * ATAPI devices have their own reset mechanism (not handled here),
- * which allows them to be individually reset without clobbering other
- * devices on the same interface. ide-cd.c will handle those separately.
+ * ATAPI devices have their own reset mechanism which allows them to be
+ * individually reset without clobbering other devices on the same interface.
*
* Unfortunately, the IDE interface does not generate an interrupt to let
* us know when the reset operation has finished, so we must poll for this.
@@ -552,15 +623,35 @@
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
* we set a timer to poll at 50ms intervals.
*/
-static int ide_do_reset (ide_drive_t *drive)
+int ide_do_reset (ide_drive_t *drive)
{
unsigned int unit;
unsigned long flags;
ide_hwif_t *hwif = HWIF(drive);
+ ide_hwgroup_t *hwgroup = HWGROUP(drive);
save_flags(flags);
cli(); /* Why ? */
+#ifdef CONFIG_BLK_DEV_IDECD
+ /* 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->keep_settings)
+ drive->unmask = 0;
+ OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
+ udelay (10);
+ hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
+ start_reset_timer (hwif); /* begin periodic polling */
+ restore_flags (flags);
+ return 1;
+ }
+ }
+ hwgroup->doing_atapi_reset = 0;
+#endif /* CONFIG_BLK_DEV_IDECD */
+
/*
* First, reset any device state data we were maintaining
* for any of the drives on this interface.
@@ -589,10 +680,10 @@
* This single interrupt gives us a "fast poll" for drives that
* recover from reset very quickly, saving us the first 50ms wait time.
*/
- OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set nIEN and SRST */
+ 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 */
- hwif->reset_timeout = jiffies + WAIT_WORSTCASE;
+ hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
start_reset_timer (hwif); /* begin periodic polling */
#endif /* OK_TO_RESET_CONTROLLER */
@@ -640,7 +731,7 @@
printk("Busy ");
else {
if (stat & READY_STAT) printk("DriveReady ");
- if (stat & WRERR_STAT) printk("WriteFault ");
+ if (stat & WRERR_STAT) printk("DeviceFault ");
if (stat & SEEK_STAT) printk("SeekComplete ");
if (stat & DRQ_STAT) printk("DataRequest ");
if (stat & ECC_STAT) printk("CorrectedError ");
@@ -746,6 +837,12 @@
if (GET_STAT() & (BUSY_STAT|DRQ_STAT))
rq->errors |= ERROR_RESET; /* Mmmm.. timing problem */
+ if (rq->errors > 3 && drive->using_dma) { /* DMA troubles? */
+ drive->using_dma = 0;
+ printk("%s: DMA disabled\n", drive->name);
+ --rq->errors;
+ return 0;
+ }
if (rq->errors >= ERROR_MAX)
ide_end_request(0, HWGROUP(drive));
else {
@@ -916,7 +1013,7 @@
* Issue a simple drive command
* The drive must be selected beforehand.
*/
-static inline void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
+static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
{
ide_set_handler (drive, handler);
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
@@ -924,6 +1021,9 @@
OUT_BYTE(cmd,IDE_COMMAND_REG);
}
+/*
+ * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
+ */
static void set_multmode_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
@@ -939,6 +1039,9 @@
IDE_DO_REQUEST;
}
+/*
+ * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
+ */
static void set_geometry_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
@@ -950,6 +1053,9 @@
IDE_DO_REQUEST;
}
+/*
+ * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
+ */
static void recal_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
@@ -961,6 +1067,10 @@
IDE_DO_REQUEST;
}
+#ifdef IDE_DRIVE_CMD
+/*
+ * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
+ */
static void drive_cmd_intr (ide_drive_t *drive)
{
byte stat = GET_STAT();
@@ -972,8 +1082,14 @@
return;
IDE_DO_REQUEST;
}
+#endif /* IDE_DRIVE_CMD */
-static void do_special (ide_drive_t *drive)
+/*
+ * 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
+ * in recent updates, and could be completely eliminated with a bit more effort.
+ */
+static inline void do_special (ide_drive_t *drive)
{
special_t *s = &drive->special;
#ifdef DEBUG
@@ -1044,6 +1160,11 @@
return 1;
}
+/*
+ * do_rw_disk() issues WIN_{MULT}READ and WIN_{MULT}WRITE commands to a disk,
+ * using LBA if supported, or CHS otherwise, to address sectors. It also takes
+ * care of issuing special DRIVE_CMDs.
+ */
static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
@@ -1075,11 +1196,15 @@
#endif
}
if (rq->cmd == READ) {
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+ return;
ide_set_handler(drive, &read_intr);
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
return;
}
if (rq->cmd == WRITE) {
+ if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
+ return;
OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk("%s: no DRQ after issuing %s\n", drive->name,
@@ -1108,6 +1233,10 @@
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return;
} else {
+ /*
+ * NULL is actually a valid way of waiting for
+ * all current requests to be flushed from the queue.
+ */
#ifdef DEBUG
printk("%s: DRIVE_CMD (null)\n", drive->name);
#endif
@@ -1120,6 +1249,9 @@
ide_end_request(0, HWGROUP(drive));
}
+/*
+ * do_request() initiates handling of a new I/O request
+ */
static inline void do_request (ide_hwif_t *hwif, struct request *rq)
{
unsigned int minor, unit;
@@ -1137,18 +1269,21 @@
goto kill_rq;
}
drive = &hwif->drives[unit];
+#ifdef DEBUG
if (rq->bh && !rq->bh->b_lock) {
printk("%s: block not locked\n", drive->name);
goto kill_rq;
}
+#endif
block = rq->sector;
blockend = block + rq->nr_sectors;
if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
- printk("%s: bad access: block=%ld, count=%ld\n",
- drive->name, block, rq->nr_sectors);
+ printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+ (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
goto kill_rq;
}
block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;
+ ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
#if (DISK_RECOVERY_TIME > 0)
while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);
#endif
@@ -1158,7 +1293,6 @@
return;
}
- ((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;
if (!drive->special.all) {
#ifdef CONFIG_BLK_DEV_IDECD
switch (drive->media) {
@@ -1202,7 +1336,6 @@
void ide_do_request (ide_hwgroup_t *hwgroup)
{
cli(); /* paranoia */
-
if (hwgroup->handler != NULL) {
printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);
return;
@@ -1218,14 +1351,25 @@
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:
- blk_dev[hwif->major].current_request = rq->next;
do_request(hwgroup->hwif = hwif, hwgroup->rq = rq);
cli();
} while (hwgroup->handler == NULL);
}
+/*
+ * do_hwgroup_request() invokes ide_do_request() after first masking
+ * all possible interrupts for the current hwgroup. This prevents race
+ * conditions in the event that an unexpected interrupt occurs while
+ * we are in the driver.
+ *
+ * Note that when an interrupt is used to reenter the driver, the first level
+ * handler will already have masked the irq that triggered, but any other ones
+ * for the hwgroup will still be unmasked. The driver tries to be careful
+ * about such things.
+ */
static void do_hwgroup_request (ide_hwgroup_t *hwgroup)
{
if (hwgroup->handler == NULL) {
@@ -1270,7 +1414,7 @@
save_flags(flags);
cli();
- if (hwgroup->hwif->reset_timeout != 0) { /* ide reset in progress? */
+ if (hwgroup->reset_timeout != 0) { /* ide reset in progress? */
if (!reset_handler(hwgroup))
do_hwgroup_request (hwgroup);
} else if (hwgroup->handler == NULL) { /* not waiting for anything? */
@@ -1278,6 +1422,8 @@
printk("%s: marginal timeout\n", drive->name);
} else { /* drive not responding */
hwgroup->handler = NULL;
+ if (hwgroup->hwif->dmaproc)
+ (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
if (!ide_error(drive, "irq timeout", GET_STAT()))
do_hwgroup_request (hwgroup);
}
@@ -1293,24 +1439,32 @@
* On laptops (and "green" PCs), an unexpected interrupt occurs whenever the
* drive enters "idle", "standby", or "sleep" mode, so if the status looks
* "good", we just ignore the interrupt completely.
+ *
+ * This routine assumes cli() is in effect when called.
+ *
+ * If an unexpected interrupt happens on irq15 while we are handling irq14
+ * and if the two interfaces are "serialized" (CMD640B), then it looks like
+ * we could screw up by interfering with a new request being set up for irq15.
+ *
+ * In reality, this is a non-issue. The new command is not sent unless the
+ * drive is ready to accept one, in which case we know the drive is not
+ * trying to interrupt us. And ide_set_handler() is always invoked before
+ * completing the issuance of any new drive command, so we will not be
+ * accidently invoked as a result of any valid command completion interrupt.
+ *
*/
static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
{
byte stat;
unsigned int unit;
ide_hwif_t *hwif = hwgroup->hwif;
- unsigned long flags;
-
- save_flags(flags);
- cli();
/*
* check for ide reset in progress
*/
- if (hwif->reset_timeout != 0) {
+ if (hwgroup->reset_timeout != 0) {
if (!reset_handler(hwgroup))
do_hwgroup_request (hwgroup);
- restore_flags(flags);
return;
}
@@ -1330,7 +1484,6 @@
}
}
} while ((hwif = hwif->next) != hwgroup->hwif);
- restore_flags(flags);
}
/*
@@ -1340,13 +1493,8 @@
{
ide_hwgroup_t *hwgroup = irq_to_hwgroup[irq];
ide_handler_t *handler;
- if (irq != hwgroup->hwif->irq) {
-#ifdef DEBUG
- printk("ide_intr: expected ira %d, got irq %d instead\n",
- hwgroup->hwif->irq, irq);
-#endif
- unexpected_intr(irq, hwgroup);
- } else if ((handler = hwgroup->handler) != NULL) {
+
+ if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
ide_drive_t *drive = hwgroup->drive;
hwgroup->handler = NULL;
del_timer(&(hwgroup->timer));
@@ -1354,12 +1502,15 @@
sti();
handler(drive);
} else {
- sti();
unexpected_intr(irq, hwgroup);
}
cli();
}
+/*
+ * get_info_ptr() returns the (ide_drive_t *) for a given device number.
+ * It returns NULL if the given device number does not match any present drives.
+ */
static ide_drive_t *get_info_ptr (int i_rdev)
{
int major = MAJOR(i_rdev);
@@ -1381,18 +1532,6 @@
}
#ifdef IDE_DRIVE_CMD
-static int write_fs_long (unsigned long useraddr, long value)
-{
- int err;
-
- if (NULL == (long *)useraddr)
- return -EINVAL;
- if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
- return err;
- put_user((unsigned)value, (long *) useraddr);
- return 0;
-}
-
/*
* This function issues a specific IDE drive command onto the
* tail of the request queue, and waits for it to be completed.
@@ -1513,7 +1652,7 @@
if ((drive = get_info_ptr(i_rdev)) == NULL)
return -ENODEV;
- major = MAJOR(i_rdev);
+ major = MAJOR(i_rdev) << 8;
minor = drive->select.b.unit << PARTN_BITS;
save_flags(flags);
cli();
@@ -1540,6 +1679,18 @@
return 0;
}
+static int write_fs_long (unsigned long useraddr, long value)
+{
+ int err;
+
+ if (NULL == (long *)useraddr)
+ return -EINVAL;
+ if ((err = verify_area(VERIFY_WRITE, (long *)useraddr, sizeof(long))))
+ return err;
+ put_user((unsigned)value, (long *) useraddr);
+ return 0;
+}
+
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -1590,6 +1741,9 @@
case HDIO_GET_UNMASKINTR:
return write_fs_long(arg, drive->unmask);
+ case HDIO_GET_DMA:
+ return write_fs_long(arg, drive->using_dma);
+
case HDIO_GET_CHIPSET:
return write_fs_long(arg, drive->chipset);
@@ -1602,13 +1756,18 @@
if (drive->id == NULL)
return -ENOMSG;
err = verify_area(VERIFY_WRITE, (char *)arg, sizeof(*drive->id));
- if (err) return err;
- memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
- return 0;
+ if (!err)
+ memcpy_tofs((char *)arg, (char *)drive->id, sizeof(*drive->id));
+ return err;
case HDIO_GET_NOWERR:
return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT);
+ case HDIO_SET_DMA:
+ if (drive->media != disk)
+ return -EPERM;
+ if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+ return -EPERM;
case HDIO_SET_KEEPSETTINGS:
case HDIO_SET_UNMASKINTR:
case HDIO_SET_NOWERR:
@@ -1622,6 +1781,9 @@
save_flags(flags);
cli();
switch (cmd) {
+ case HDIO_SET_DMA:
+ drive->using_dma = arg;
+ break;
case HDIO_SET_KEEPSETTINGS:
drive->keep_settings = arg;
break;
@@ -1645,7 +1807,8 @@
return 0;
case HDIO_SET_MULTCOUNT:
- if (!suser()) return -EACCES;
+ if (!suser())
+ return -EACCES;
if (inode->i_rdev & PARTN_MASK)
return -EINVAL;
if ((drive->id != NULL) && (arg > drive->id->max_multsect))
@@ -1738,13 +1901,13 @@
*p++ = '\0';
}
-static void do_identify (ide_drive_t *drive, byte cmd)
+static inline void do_identify (ide_drive_t *drive, byte cmd)
{
int bswap;
struct hd_driveid *id;
unsigned long capacity, check;
- id = drive->id = ide_alloc(SECTOR_WORDS*4);
+ id = drive->id = ide_alloc (SECTOR_WORDS*4, 0);
ide_input_data(drive, id, SECTOR_WORDS); /* read 512 bytes of id info */
sti();
@@ -1764,11 +1927,11 @@
*/
bswap = 1;
if (cmd == WIN_PIDENTIFY) {
- if ((id->model[0] == 'N' && id->model[1] == 'E')
- || (id->model[0] == 'F' && id->model[1] == 'X')
- || (id->model[0] == 'P' && id->model[1] == 'i'))
- bswap = 0; /* NEC, Pioneer and *some* Mitsumi units */
- } /* Vertos drives may still be weird */
+ if ((id->model[0] == 'N' && id->model[1] == 'E') /* NEC */
+ || (id->model[0] == 'F' && id->model[1] == 'X') /* Mitsumi */
+ || (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
+ bswap = 0; /* Vertos drives may still be weird */
+ }
fixstring (id->model, sizeof(id->model), bswap);
fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
fixstring (id->serial_no, sizeof(id->serial_no), bswap);
@@ -1862,7 +2025,10 @@
drive->mult_req = id->max_multsect;
if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))
drive->special.b.set_multmode = 1;
- printk(", MaxMult=%d", id->max_multsect);
+ }
+ if (HWIF(drive)->dmaproc != NULL) { /* hwif supports DMA? */
+ if (!(HWIF(drive)->dmaproc(ide_dma_check, drive)))
+ printk(", DMA");
}
printk("\n");
}
@@ -1998,7 +2164,7 @@
* Returns: 0 no device was found
* 1 device was found (note: drive->present might still be 0)
*/
-static byte probe_for_drive (ide_drive_t *drive)
+static inline byte probe_for_drive (ide_drive_t *drive)
{
if (drive->noprobe) /* skip probing? */
return drive->present;
@@ -2306,6 +2472,7 @@
* 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. A non-zero value
* means we have an AT controller hard disk for that drive.
*/
+
static void probe_cmos_for_drives (ide_hwif_t *hwif)
{
#ifdef __i386__
@@ -2320,11 +2487,9 @@
ide_drive_t *drive = &hwif->drives[unit];
if ((cmos_disks & (0xf0 >> (unit*4))) && !drive->present) {
drive->cyl = drive->bios_cyl = *(unsigned short *)BIOS;
- drive->head = drive->bios_head = * (BIOS+2);
- drive->sect = drive->bios_sect = * (BIOS+14);
- drive->wpcom = (*(unsigned short *)(BIOS+5))>>2;
+ drive->head = drive->bios_head = *(BIOS+2);
+ drive->sect = drive->bios_sect = *(BIOS+14);
drive->ctl = *(BIOS+8);
- drive->wpcom = 0;
drive->media = disk;
drive->present = 1;
}
@@ -2362,12 +2527,16 @@
* Got the irq, now set everything else up
*/
if ((hwgroup = irq_to_hwgroup[hwif->irq]) == NULL) {
- hwgroup = ide_alloc(sizeof(ide_hwgroup_t));
+ hwgroup = ide_alloc (sizeof(ide_hwgroup_t), 0);
irq_to_hwgroup[hwif->irq] = hwgroup;
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 */
init_timer(&hwgroup->timer);
hwgroup->timer.function = &timer_expiry;
hwgroup->timer.data = (unsigned long) hwgroup;
@@ -2456,6 +2625,7 @@
}
#endif /* SUPPORT_DTC2278 */
+
/*
* This is gets invoked once during initialization, to set *everything* up
*/
@@ -2463,7 +2633,7 @@
{
int h;
- init_mem_start = (mem_start + 3uL) & ~3uL; /* for ide_alloc() */
+ ide_mem_start = mem_start; /* for ide_alloc () */
init_ide_data ();
/*
* First, we determine what hardware is present
@@ -2472,6 +2642,20 @@
if (probe_dtc2278)
try_to_init_dtc2278();
#endif /* SUPPORT_DTC2278 */
+#ifdef CONFIG_PCI
+ /*
+ * Look for pci disk interfaces.
+ */
+ if (pcibios_present()) {
+#ifdef CONFIG_BLK_DEV_TRITON
+ ide_init_triton (ide_hwifs);
+#endif /* CONFIG_BLK_DEV_TRITON */
+ }
+#endif /* CONFIG_PCI */
+
+ /*
+ * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
+ */
for (h = 0; h < MAX_HWIFS; ++h) {
ide_hwif_t *hwif = &ide_hwifs[h];
if (!hwif->noprobe) {
@@ -2491,6 +2675,7 @@
if (hwif->irq == HD_IRQ && hwif->io_base != HD_DATA) {
printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
hwif->present = 0;
+B
}
#endif /* CONFIG_BLK_DEV_HD */
}
@@ -2535,7 +2720,7 @@
hwif->present = 1; /* success */
}
}
- mem_start = init_mem_start;
- init_mem_start = 0uL; /* prevent further use of ide_alloc() */
+ mem_start = ide_mem_start;
+ ide_mem_start = 0uL; /* prevent further use of ide_alloc() */
return mem_start;
}
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected]
with Sam's (original) version of this