summaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-03 01:22:27 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-03 01:22:27 +0000
commitf9bbe9da79dbc8557c74efeb158b431cd67ace52 (patch)
tree3220d014a35f9d88a48668a1468524e988daebff /drivers/block
parent3d697109c1ff85ef563aec3d5e113ef225ed2792 (diff)
Upgrade to 2.1.73.
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/Config.in24
-rw-r--r--drivers/block/Makefile18
-rw-r--r--drivers/block/ali14xx.c1
-rw-r--r--drivers/block/cmd640.c1
-rw-r--r--drivers/block/dtc2278.c1
-rw-r--r--drivers/block/ht6560b.c2
-rw-r--r--drivers/block/ide-cd.c93
-rw-r--r--drivers/block/ide-cd.h10
-rw-r--r--drivers/block/ide-disk.c65
-rw-r--r--drivers/block/ide-dma.c473
-rw-r--r--drivers/block/ide-floppy.c113
-rw-r--r--drivers/block/ide-pci.c382
-rw-r--r--drivers/block/ide-probe.c107
-rw-r--r--drivers/block/ide-proc.c505
-rw-r--r--drivers/block/ide-tape.c141
-rw-r--r--drivers/block/ide.c252
-rw-r--r--drivers/block/ide.h93
-rw-r--r--drivers/block/ll_rw_blk.c26
-rw-r--r--drivers/block/ns87415.c228
-rw-r--r--drivers/block/opti621.c28
-rw-r--r--drivers/block/pdc4030.c8
-rw-r--r--drivers/block/qd6580.c1
-rw-r--r--drivers/block/rz1000.c43
-rw-r--r--drivers/block/trm290.c181
-rw-r--r--drivers/block/umc8672.c1
25 files changed, 1867 insertions, 930 deletions
diff --git a/drivers/block/Config.in b/drivers/block/Config.in
index 220148670..b76e9af08 100644
--- a/drivers/block/Config.in
+++ b/drivers/block/Config.in
@@ -23,26 +23,28 @@ else
fi
if [ "$CONFIG_PCI" = "y" ]; then
bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
- bool ' PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
- if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+ bool ' Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
+ if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+ bool ' Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' Tekram TRM290 DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
- bool ' OPTi 82C621 enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+ bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+ bool ' OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
+ bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
fi
fi
fi
bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS
if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
comment 'Note: most of these also require special kernel boot parameters'
- bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
- bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
- bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
- bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+ bool ' Generic 4 drives/port support' CONFIG_BLK_DEV_4DRIVES
+ bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX
+ bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278
+ bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B
+ bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
+ bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
+ bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030
fi
- bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580
- bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672
fi
fi
fi
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 50e9f6be6..f992a98a5 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -79,11 +79,17 @@ L_OBJS += hd.o
endif
ifeq ($(CONFIG_BLK_DEV_IDE),y)
-LX_OBJS += ide.o
-L_OBJS += ide-probe.o
+ LX_OBJS += ide.o
+ ifeq ($(CONFIG_PROC_FS),y)
+ L_OBJS += ide-proc.o
+ endif
+ L_OBJS += ide-probe.o
else
ifeq ($(CONFIG_BLK_DEV_IDE),m)
MX_OBJS += ide.o
+ ifeq ($(CONFIG_PROC_FS),y)
+ M_OBJS += ide-proc.o
+ endif
M_OBJS += ide-probe.o
endif
endif
@@ -96,6 +102,10 @@ ifeq ($(CONFIG_BLK_DEV_CMD640),y)
L_OBJS += cmd640.o
endif
+ifeq ($(CONFIG_BLK_DEV_IDEPCI),y)
+L_OBJS += ide-pci.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_IDEDMA),y)
L_OBJS += ide-dma.o
endif
@@ -137,6 +147,10 @@ ifeq ($(CONFIG_BLK_DEV_OPTI621),y)
L_OBJS += opti621.o
endif
+ifeq ($(CONFIG_BLK_DEV_NS87415),y)
+L_OBJS += ns87415.o
+endif
+
ifeq ($(CONFIG_BLK_DEV_IDEDISK),y)
L_OBJS += ide-disk.o
else
diff --git a/drivers/block/ali14xx.c b/drivers/block/ali14xx.c
index 5f6c0f437..c0c7762d6 100644
--- a/drivers/block/ali14xx.c
+++ b/drivers/block/ali14xx.c
@@ -213,6 +213,7 @@ void init_ali14xx (void)
ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
/* initialize controller registers */
if (!initRegisters()) {
diff --git a/drivers/block/cmd640.c b/drivers/block/cmd640.c
index e833a2bd0..5ffbefaf0 100644
--- a/drivers/block/cmd640.c
+++ b/drivers/block/cmd640.c
@@ -797,6 +797,7 @@ int ide_probe_for_cmd640x (void)
cmd_hwif1->chipset = ide_cmd640;
cmd_hwif0->mate = cmd_hwif1;
cmd_hwif1->mate = cmd_hwif0;
+ cmd_hwif1->channel = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
cmd_hwif1->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff --git a/drivers/block/dtc2278.c b/drivers/block/dtc2278.c
index 30988bd99..63b9143b6 100644
--- a/drivers/block/dtc2278.c
+++ b/drivers/block/dtc2278.c
@@ -127,4 +127,5 @@ void init_dtc2278 (void)
ide_hwifs[1].drives[1].no_unmask = 1;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
}
diff --git a/drivers/block/ht6560b.c b/drivers/block/ht6560b.c
index 9d888cfc0..b739f39ee 100644
--- a/drivers/block/ht6560b.c
+++ b/drivers/block/ht6560b.c
@@ -155,7 +155,6 @@ static void ht6560b_selectproc (ide_drive_t *drive)
printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, t, timing);
#endif
}
- OUT_BYTE(drive->select.all,IDE_SELECT_REG);
}
/*
@@ -229,6 +228,7 @@ void init_ht6560b (void)
ide_hwifs[1].serialized = 1;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
} else
printk("\nht6560b: not found\n");
}
diff --git a/drivers/block/ide-cd.c b/drivers/block/ide-cd.c
index 02f97ec6f..3a8e48722 100644
--- a/drivers/block/ide-cd.c
+++ b/drivers/block/ide-cd.c
@@ -2,7 +2,7 @@
/*
* linux/drivers/block/ide-cd.c
* Copyright (C) 1994, 1995, 1996 scott snyder <snyder@fnald0.fnal.gov>
- * Copyright (C) 1996, 1997 Erik Andersen <andersee@debian.org>
+ * Copyright (C) 1996-1998 Erik Andersen <andersee@debian.org>
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
@@ -27,13 +27,6 @@
* unless you have a patch to fix it. I am working on it...)
* -Implement ide_cdrom_select_speed using the generic cdrom interface
* -Fix ide_cdrom_reset so that it works (it does nothing right now)
- * -When trying to mount a cdrom with the tray open, you get an billion
- * "tray open or drive not ready" messages until the tray gets closed.
- * This is because ide-cd does not properly return drive_status immediatly,
- * but instead waits for the drive to close first (bad, bad, bad)
- * and keeps on trying, and failing... This bug was revealed by the
- * recent changes to the Uniform CD-ROm driver, and I havn't had a
- * chance to fix it yet.
*
* MOSTLY DONE LIST:
* Query the drive to find what features are available
@@ -185,8 +178,13 @@
* Added identifier so new Sanyo CD-changer works
* Better detection if door locking isn't supported
*
+ * 4.06 Dec 17, 1997 -- fixed endless "tray open" messages -ml
+ * 4.07 Dec 17, 1997 -- fallback to set pc->stat on "tray open"
+ *
*************************************************************************/
+#define IDECD_VERSION "4.07"
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -194,11 +192,8 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/malloc.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/cdrom.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -418,7 +413,8 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive)
(struct packet_command *)
pc->sense_data);
}
-
+ if (rq->cmd == READ && !rq->current_nr_sectors)
+ uptodate = 1;
ide_end_request (uptodate, HWGROUP(drive));
}
@@ -443,7 +439,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
sense_key = err >> 4;
if (rq == NULL)
- printk ("%s : missing request in cdrom_decode_status\n",
+ printk ("%s: missing request in cdrom_decode_status\n",
drive->name);
else {
cmd = rq->cmd;
@@ -477,16 +473,13 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
because workman constantly polls the drive
with this command, and we don't want
to uselessly fill up the syslog. */
- if (pc->c[0] != SCMD_READ_SUBCHANNEL) {
+ if (pc->c[0] != SCMD_READ_SUBCHANNEL)
printk ("%s: tray open or drive not ready\n",
drive->name);
- return 1;
- }
} else if (sense_key == UNIT_ATTENTION) {
/* Check for media change. */
cdrom_saw_media_change (drive);
- printk (" %s: media changed\n", drive->name);
- return 0;
+ printk ("%s: media changed\n", drive->name);
} else {
/* Otherwise, print an error. */
ide_dump_status (drive, "packet command error",
@@ -521,7 +514,7 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat,
cdrom_saw_media_change (drive);
/* Fail the request. */
- printk ("%s : tray open\n", drive->name);
+ printk ("%s: tray open\n", drive->name);
cdrom_end_request (0, drive);
} else if (sense_key == UNIT_ATTENTION) {
/* Media change. */
@@ -591,7 +584,6 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
if (info->dma)
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
-
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
ide_set_handler (drive, handler, WAIT_CMD);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
@@ -619,7 +611,8 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive,
int stat_dum;
/* Check for errors. */
- if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum)) return 1;
+ if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum))
+ return 1;
} else {
/* Otherwise, we must wait for DRQ to get set. */
if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))
@@ -746,12 +739,12 @@ static void cdrom_read_intr (ide_drive_t *drive)
/* Check for errors. */
if (dma) {
info->dma = 0;
- if ((dma_error = HWIF(drive)->dmaproc(ide_dma_status_bad, drive)))
+ if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
HWIF(drive)->dmaproc(ide_dma_off, drive);
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive));
}
- if (cdrom_decode_status (drive, 0, &stat)) return;
+ if (cdrom_decode_status (drive, 0, &stat))
+ return;
if (dma) {
if (!dma_error) {
@@ -764,7 +757,6 @@ static void cdrom_read_intr (ide_drive_t *drive)
return;
}
-
/* Read the interrupt reason and the transfer length. */
ireason = IN_BYTE (IDE_NSECTOR_REG);
len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);
@@ -779,7 +771,6 @@ static void cdrom_read_intr (ide_drive_t *drive)
cdrom_end_request (0, drive);
} else
cdrom_end_request (1, drive);
-
return;
}
@@ -990,7 +981,8 @@ static void cdrom_seek_intr (ide_drive_t *drive)
int stat;
static int retry = 10;
- if (cdrom_decode_status (drive, 0, &stat)) return;
+ if (cdrom_decode_status (drive, 0, &stat))
+ return;
CDROM_CONFIG_FLAGS(drive)->seeking = 1;
if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
@@ -1088,7 +1080,8 @@ static void cdrom_pc_intr (ide_drive_t *drive)
struct packet_command *pc = (struct packet_command *)rq->buffer;
/* Check for errors. */
- if (cdrom_decode_status (drive, 0, &stat)) return;
+ if (cdrom_decode_status (drive, 0, &stat))
+ return;
/* Read the interrupt reason and the transfer length. */
ireason = IN_BYTE (IDE_NSECTOR_REG);
@@ -1251,8 +1244,11 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
ide_init_drive_cmd (&req);
req.cmd = PACKET_COMMAND;
req.buffer = (char *)pc;
- (void) ide_do_drive_cmd (drive, &req, ide_wait);
-
+ if (ide_do_drive_cmd (drive, &req, ide_wait)) {
+ printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n",
+ drive->name, req.buffer[0], req.buffer[1]);
+ /* FIXME: we should probably abort/retry or something */
+ }
if (pc->stat != 0) {
/* The request failed. Retry if it was due to a unit
attention status
@@ -2692,7 +2688,7 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
static
int ide_cdrom_probe_capabilities (ide_drive_t *drive)
{
- int stat, nslots;
+ int stat, nslots, attempts = 3;
struct {
char pad[8];
struct atapi_capabilities_page cap;
@@ -2703,14 +2699,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
if (CDROM_CONFIG_FLAGS (drive)->nec260)
return nslots;
- stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
- (char *)&buf, sizeof (buf), NULL);
- if (stat)
- return nslots;
+ do { /* we seem to get stat=0x01,err=0x00 the first time (??) */
+ if (attempts-- <= 0)
+ return 0;
+ stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0,
+ (char *)&buf, sizeof (buf), NULL);
+ } while (stat);
if (buf.cap.lock == 0)
CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
-
if (buf.cap.cd_r_write)
CDROM_CONFIG_FLAGS (drive)->cd_r = 1;
if (buf.cap.cd_rw_write)
@@ -2737,11 +2734,15 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
}
}
- CDROM_STATE_FLAGS (drive)->curent_speed = ntohs(buf.cap.curspeed)/176;
- CDROM_CONFIG_FLAGS (drive)->max_speed = ntohs(buf.cap.maxspeed)/176;
+ if (drive->id && drive->id->model[0]) {
+ CDROM_STATE_FLAGS (drive)->current_speed = (ntohs(buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176;
+ } else { /* no-name ACERs (AOpen) have it backwards */
+ CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176;
+ CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176;
+ }
- stat=0;
- printk ("%s: ATAPI %dx CDROM",
+ printk ("%s: ATAPI %dX CDROM",
drive->name, CDROM_CONFIG_FLAGS (drive)->max_speed);
if (CDROM_CONFIG_FLAGS (drive)->cd_r|CDROM_CONFIG_FLAGS (drive)->cd_rw)
printk (" CD%s%s",
@@ -2827,7 +2828,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
else if (strcmp (drive->id->model,
"NEC CD-ROM DRIVE:260") == 0 &&
- strcmp (drive->id->fw_rev, "1.01") == 0) {
+ strncmp (drive->id->fw_rev, "1.01", 4) == 0) { /* FIXME */
/* Old NEC260 (not R).
This drive was released before the 1.2 version
of the spec. */
@@ -2838,7 +2839,7 @@ int ide_cdrom_setup (ide_drive_t *drive)
}
else if (strcmp (drive->id->model, "WEARNES CDD-120") == 0 &&
- strcmp (drive->id->fw_rev, "A1.1") == 0) {
+ strncmp (drive->id->fw_rev, "A1.1", 4) == 0) { /* FIXME */
/* Wearnes */
CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1;
CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1;
@@ -2936,21 +2937,23 @@ static ide_module_t ide_cdrom_module = {
};
static ide_driver_t ide_cdrom_driver = {
+ "ide-cdrom", /* name */
+ IDECD_VERSION, /* version */
ide_cdrom, /* media */
0, /* busy */
1, /* supports_dma */
1, /* supports_dsc_overlap */
ide_cdrom_cleanup, /* cleanup */
ide_do_rw_cdrom, /* do_request */
- NULL, /* ??? or perhaps
- cdrom_end_request? */
+ NULL, /* ??? or perhaps cdrom_end_request? */
ide_cdrom_ioctl, /* ioctl */
ide_cdrom_open, /* open */
ide_cdrom_release, /* release */
ide_cdrom_check_media_change, /* media_change */
NULL, /* pre_reset */
NULL, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h
index afb3e5dbe..53e38e1b1 100644
--- a/drivers/block/ide-cd.h
+++ b/drivers/block/ide-cd.h
@@ -119,11 +119,11 @@ struct ide_cd_config_flags {
__u8 cd_rw : 1; /* Drive can write to CD-R/W media . */
__u8 supp_disc_present: 1; /* Changer can report exact contents
of slots. */
- __u8 max_speed : 4; /* Max speed of the drive */
__u8 seeking : 1; /* Seeking in progress */
__u8 reserved : 6;
+ byte max_speed; /* Max speed of the drive */
};
-#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_cyl))
+#define CDROM_CONFIG_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->config_flags))
/* State flags. These give information about the current state of the
@@ -133,10 +133,10 @@ struct ide_cd_state_flags {
__u8 toc_valid : 1; /* Saved TOC information is current. */
__u8 door_locked : 1; /* We think that the drive door is locked. */
__u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */
- __u8 curent_speed : 4; /* Current speed of the drive */
__u8 reserved : 3;
+ byte current_speed; /* Current speed of the drive */
};
-#define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head))
+#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
struct atapi_request_sense {
@@ -385,6 +385,8 @@ struct cdrom_info {
/* Buffer to hold mechanism status and changer slot table. */
struct atapi_changer_info *changer_info;
+ struct ide_cd_config_flags config_flags;
+ struct ide_cd_state_flags state_flags;
/* Per-device info needed by cdrom.c generic driver. */
struct cdrom_device_info devinfo;
diff --git a/drivers/block/ide-disk.c b/drivers/block/ide-disk.c
index f75a1a5be..5e178b6cd 100644
--- a/drivers/block/ide-disk.c
+++ b/drivers/block/ide-disk.c
@@ -10,32 +10,6 @@
*
* This is the IDE/ATA disk driver, as evolved from hd.c and ide.c.
*
- * From hd.c:
- * |
- * | It traverses the request-list, using interrupts to jump between functions.
- * | As nearly all functions can be called within interrupts, we may not sleep.
- * | Special care is recommended. Have Fun!
- * |
- * | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- * |
- * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- * | in the early extended-partition checks and added DM partitions.
- * |
- * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- * |
- * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- * | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg)
- * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2")
- * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom)
- *
- * This was a rewrite of just about everything from hd.c, though some original
- * code is still sprinkled about. Think of it as a major evolution, with
- * inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- *
* Version 1.00 move disk only code from ide.c to ide-disk.c
* support optional byte-swapping of all data
* Version 1.01 fix previous byte-swapping code
@@ -43,6 +17,8 @@
* Verions 1.03 fix display of id->buf_size for big-endian
*/
+#define IDEDISK_VERSION "1.03"
+
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/config.h>
@@ -52,12 +28,9 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
#include <linux/delay.h>
@@ -319,7 +292,7 @@ static void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long bl
OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
#ifdef CONFIG_BLK_DEV_PDC4030
if (IS_PDC4030_DRIVE) {
- if (hwif->is_pdc4030_2 || rq->cmd == READ) {
+ if (hwif->channel != 0 || rq->cmd == READ) {
use_pdc4030_io = 1;
}
}
@@ -494,6 +467,11 @@ static void idedisk_pre_reset (ide_drive_t *drive)
drive->special.b.set_multmode = 1;
}
+static ide_proc_entry_t idedisk_proc[] = {
+ { "geometry", proc_ide_read_geometry, NULL },
+ { NULL, NULL, NULL }
+};
+
int idedisk_init (void);
static ide_module_t idedisk_module = {
IDE_DRIVER_MODULE,
@@ -505,6 +483,8 @@ static ide_module_t idedisk_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idedisk_driver = {
+ "ide-disk", /* name */
+ IDEDISK_VERSION, /* version */
ide_disk, /* media */
0, /* busy */
1, /* supports_dma */
@@ -518,7 +498,8 @@ static ide_driver_t idedisk_driver = {
idedisk_media_change, /* media_change */
idedisk_pre_reset, /* pre_reset */
idedisk_capacity, /* capacity */
- idedisk_special /* special */
+ idedisk_special, /* special */
+ idedisk_proc /* proc */
};
static int idedisk_cleanup (ide_drive_t *drive)
@@ -526,20 +507,6 @@ static int idedisk_cleanup (ide_drive_t *drive)
return ide_unregister_subdriver(drive);
}
-static int idedisk_identify_device (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
-
- if (id == NULL)
- return 0;
-
- /* SunDisk drives: force one unit */
- if (id->model[0] == 'S' && id->model[1] == 'u' && (drive->select.all & (1<<4)))
- return 1;
-
- return 0;
-}
-
static void idedisk_setup (ide_drive_t *drive)
{
struct hd_driveid *id = drive->id;
@@ -554,7 +521,7 @@ static void idedisk_setup (ide_drive_t *drive)
drive->removable = 1;
}
- /* SunDisk drives: treat as non-removable */
+ /* SunDisk drives: treat as non-removable; can mess up non-Sun systems! FIXME */
if (id->model[0] == 'S' && id->model[1] == 'u')
drive->removable = 0;
@@ -634,8 +601,12 @@ int idedisk_init (void)
MOD_INC_USE_COUNT;
while ((drive = ide_scan_devices (ide_disk, NULL, failed++)) != NULL) {
- if (idedisk_identify_device (drive))
+
+ /* SunDisk drives: ignore "second" drive; can mess up non-Sun systems! FIXME */
+ struct hd_driveid *id = drive->id;
+ if (id && id->model[0] == 'S' && id->model[1] == 'u' && drive->select.b.unit)
continue;
+
if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
continue;
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c
index 6a2886f78..bba735580 100644
--- a/drivers/block/ide-dma.c
+++ b/drivers/block/ide-dma.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-dma.c Version 4.06 December 3, 1997
+ * linux/drivers/block/ide-dma.c Version 4.07 December 5, 1997
*
* Copyright (c) 1995-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
@@ -49,9 +49,8 @@
* available from ftp://ftp.intel.com/pub/bios/10004bs0.exe
* (thanks to Glen Morrell <glen@spin.Stanford.edu> for researching this).
*
- * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for fixing the
- * problem with some (all?) ACER motherboards/BIOSs. Hopefully the fix
- * still works here (?).
+ * Thanks to "Christopher J. Reimer" <reimer@doe.carleton.ca> for
+ * fixing the problem with the BIOS on some Acer motherboards.
*
* Thanks to "Benoit Poulot-Cazajous" <poulot@chorus.fr> for testing
* "TX" chipset compatibility and for providing patches for the "TX" chipset.
@@ -69,16 +68,12 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
#include <linux/pci.h>
#include <linux/bios32.h>
-#include <linux/init.h>
#include <asm/io.h>
-#include <asm/dma.h>
+#include <asm/irq.h>
#include "ide.h"
@@ -110,23 +105,19 @@ const char *good_dma_drives[] = {"Micropolis 2112A",
#define PRD_BYTES 8
#define PRD_ENTRIES (PAGE_SIZE / (2 * PRD_BYTES))
-static int config_drive_for_dma (ide_drive_t *);
-
/*
* dma_intr() is the handler for disk read/write DMA interrupts
*/
-static void dma_intr (ide_drive_t *drive)
+void ide_dma_intr (ide_drive_t *drive)
{
- byte stat, dma_stat;
int i;
- struct request *rq = HWGROUP(drive)->rq;
- unsigned short dma_base = HWIF(drive)->dma_base;
+ byte stat, dma_stat;
- dma_stat = inb(dma_base+2); /* get DMA status */
- outb(inb(dma_base)&~1, dma_base); /* stop DMA operation */
+ dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
stat = GET_STAT(); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
- if ((dma_stat & 7) == 4) { /* verify good DMA status */
+ if (!dma_stat) {
+ struct request *rq = HWGROUP(drive)->rq;
rq = HWGROUP(drive)->rq;
for (i = rq->nr_sectors; i > 0;) {
i -= rq->current_nr_sectors;
@@ -134,7 +125,7 @@ static void dma_intr (ide_drive_t *drive)
}
return;
}
- printk("%s: bad DMA status: 0x%02x\n", drive->name, dma_stat);
+ printk("%s: dma_intr: bad DMA status\n", drive->name);
}
sti();
ide_error(drive, "dma_intr", stat);
@@ -195,23 +186,46 @@ int ide_build_dmatable (ide_drive_t *drive)
unsigned long xcount, bcount = 0x10000 - (addr & 0xffff);
if (bcount > size)
bcount = size;
- *table++ = addr;
+ *table++ = cpu_to_le32(addr);
xcount = bcount & 0xffff;
if (is_trm290_chipset)
xcount = ((xcount >> 2) - 1) << 16;
- *table++ = xcount;
+ *table++ = cpu_to_le32(xcount);
addr += bcount;
size -= bcount;
}
}
} while (bh != NULL);
- if (count) {
- if (!is_trm290_chipset)
- *--table |= 0x80000000; /* set End-Of-Table (EOT) bit */
- return count;
+ if (!count)
+ printk("%s: empty DMA table?\n", drive->name);
+ else if (!is_trm290_chipset)
+ *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */
+ return count;
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+ const char **list;
+ struct hd_driveid *id = drive->id;
+ ide_hwif_t *hwif = HWIF(drive);
+
+ if (id && (id->capability & 1) && !HWIF(drive)->no_autodma) {
+ /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
+ if (id->field_valid & 4) /* UltraDMA */
+ if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
+ return hwif->dmaproc(ide_dma_on, drive);
+ /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
+ if (id->field_valid & 2) /* regular DMA */
+ if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
+ return hwif->dmaproc(ide_dma_on, drive);
+ /* Consult the list of known "good" drives */
+ list = good_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model))
+ return hwif->dmaproc(ide_dma_on, drive);
+ }
}
- printk("%s: empty DMA table?\n", drive->name);
- return 0;
+ return hwif->dmaproc(ide_dma_off_quietly, drive);
}
/*
@@ -233,7 +247,7 @@ int ide_build_dmatable (ide_drive_t *drive)
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned long dma_base = hwif->dma_base;
+ unsigned int dma_base = hwif->dma_base;
unsigned int count, reading = 0;
switch (func) {
@@ -243,21 +257,8 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
case ide_dma_on:
drive->using_dma = (func == ide_dma_on);
return 0;
- case ide_dma_abort:
- outb(inb(dma_base)&~1, dma_base); /* stop DMA */
- return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
- case ide_dma_status_bad:
- return ((inb(dma_base+2) & 7) != 4); /* verify good DMA status */
- case ide_dma_transferred:
- return 0; /* NOT IMPLEMENTED: number of bytes actually transferred */
- case ide_dma_begin:
- outb(inb(dma_base)|1, dma_base); /* begin DMA */
- return 0;
- default:
- printk("ide_dmaproc: unsupported func: %d\n", func);
- return 1;
case ide_dma_read:
reading = 1 << 3;
case ide_dma_write:
@@ -268,50 +269,37 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */
if (drive->media != ide_disk)
return 0;
- ide_set_handler(drive, &dma_intr, WAIT_CMD); /* issue cmd to drive */
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);/* issue cmd to drive */
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
- outb(inb(dma_base)|1, dma_base); /* begin DMA */
+ case ide_dma_begin:
+ outb(inb(dma_base)|1, dma_base); /* start DMA */
return 0;
- }
-}
-
-static int config_drive_for_dma (ide_drive_t *drive)
-{
- const char **list;
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
-
- if (id && (id->capability & 1)) {
- /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */
- if (id->field_valid & 4) /* UltraDMA */
- if ((id->dma_ultra & (id->dma_ultra >> 8) & 7))
- return hwif->dmaproc(ide_dma_on, drive);
- /* Enable DMA on any drive that has mode2 DMA (multi or single) enabled */
- if (id->field_valid & 2) /* regular DMA */
- if ((id->dma_mword & 0x404) == 0x404 || (id->dma_1word & 0x404) == 0x404)
- return hwif->dmaproc(ide_dma_on, drive);
- /* Consult the list of known "good" drives */
- list = good_dma_drives;
- while (*list) {
- if (!strcmp(*list++,id->model))
- return hwif->dmaproc(ide_dma_on, drive);
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
+ {
+ byte dma_stat = inb(dma_base+2);
+ int rc = (dma_stat & 7) != 4;
+ outb(inb(dma_base)&~1, dma_base); /* stop DMA */
+ outb(dma_stat|6, dma_base+2); /* clear the INTR & ERROR bits */
+ return rc; /* verify good DMA status */
}
+ default:
+ printk("ide_dmaproc: unsupported func: %d\n", func);
+ return 1;
}
- return hwif->dmaproc(ide_dma_off_quietly, drive);
}
-void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports)
+void ide_setup_dma (ide_hwif_t *hwif, unsigned int dma_base, unsigned int num_ports) /* __init */
{
static unsigned long dmatable = 0;
static unsigned leftover = 0;
- printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dmabase, dmabase + num_ports - 1);
- if (check_region(dmabase, num_ports)) {
+ printk(" %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dma_base, dma_base + num_ports - 1);
+ if (check_region(dma_base, num_ports)) {
printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
return;
}
- request_region(dmabase, num_ports, hwif->name);
- hwif->dma_base = dmabase;
+ request_region(dma_base, num_ports, hwif->name);
+ hwif->dma_base = dma_base;
if (leftover < (PRD_ENTRIES * PRD_BYTES)) {
/*
* The BM-DMA uses full 32bit addr, so we can
@@ -328,87 +316,18 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_p
dmatable += (PRD_ENTRIES * PRD_BYTES);
leftover -= (PRD_ENTRIES * PRD_BYTES);
hwif->dmaproc = &ide_dmaproc;
+
if (hwif->chipset != ide_trm290) {
- byte dma_stat = inb(dmabase+2);
- printk(", BIOS DMA settings: %s:%s %s:%s",
- hwif->drives[0].name, (dma_stat & 0x20) ? "yes" : "no ",
- hwif->drives[1].name, (dma_stat & 0x40) ? "yes" : "no");
+ byte dma_stat = inb(dma_base+2);
+ printk(", BIOS settings: %s:%s, %s:%s",
+ hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
+ hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
}
printk("\n");
}
}
-#ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(byte, byte, ide_hwif_t *);
-#define INIT_TRM290 (&ide_init_trm290)
-#else
-#define INIT_TRM290 (NULL)
-#endif /* CONFIG_BLK_DEV_TRM290 */
-
-#ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(byte, byte, ide_hwif_t *);
-#define INIT_OPTI (&ide_init_opti621)
-#else
-#define INIT_OPTI (NULL)
-#endif /* CONFIG_BLK_DEV_OPTI621 */
-
-#define DEVID_PIIX (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371_1 <<16))
-#define DEVID_PIIX3 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371SB_1 <<16))
-#define DEVID_PIIX4 (PCI_VENDOR_ID_INTEL |(PCI_DEVICE_ID_INTEL_82371AB <<16))
-#define DEVID_VP_IDE (PCI_VENDOR_ID_VIA |(PCI_DEVICE_ID_VIA_82C586_1 <<16))
-#define DEVID_PDC20246 (PCI_VENDOR_ID_PROMISE|(PCI_DEVICE_ID_PROMISE_20246 <<16))
-#define DEVID_RZ1000 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1000 <<16))
-#define DEVID_RZ1001 (PCI_VENDOR_ID_PCTECH |(PCI_DEVICE_ID_PCTECH_RZ1001 <<16))
-#define DEVID_CMD640 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_640 <<16))
-#define DEVID_CMD646 (PCI_VENDOR_ID_CMD |(PCI_DEVICE_ID_CMD_646 <<16))
-#define DEVID_SIS5513 (PCI_VENDOR_ID_SI |(PCI_DEVICE_ID_SI_5513 <<16))
-#define DEVID_OPTI (PCI_VENDOR_ID_OPTI |(PCI_DEVICE_ID_OPTI_82C621 <<16))
-#define DEVID_OPTI2 (PCI_VENDOR_ID_OPTI |(0xd568 /* from datasheets */ <<16))
-#define DEVID_TRM290 (PCI_VENDOR_ID_TEKRAM |(PCI_DEVICE_ID_TEKRAM_DC290 <<16))
-#define DEVID_NS87410 (PCI_VENDOR_ID_NS |(PCI_DEVICE_ID_NS_87410 <<16))
-#define DEVID_HT6565 (PCI_VENDOR_ID_HOLTEK |(PCI_DEVICE_ID_HOLTEK_6565 <<16))
-
-typedef struct ide_pci_enablebit_s {
- byte reg; /* byte pci reg holding the enable-bit */
- byte mask; /* mask to isolate the enable-bit */
- byte val; /* value of masked reg when "enabled" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
- unsigned int id;
- const char *name;
- void (*init_hwif)(byte bus, byte fn, ide_hwif_t *hwif);
- ide_pci_enablebit_t enablebits[2];
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] = {
- {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
- {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
- {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
- {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
- {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} },
- {DEVID_RZ1000, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_RZ1001, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_CMD640, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_OPTI, "OPTI", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
- {DEVID_OPTI2, "OPTI2", INIT_OPTI, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
- {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} },
- {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} },
- {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} },
- {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
- {0, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
-
-__initfunc(static ide_pci_device_t *lookup_devid(unsigned int devid))
-{
- ide_pci_device_t *d = ide_pci_chipsets;
- while (d->id && d->id != devid)
- ++d;
- return d;
-}
-
-/* The next two functions were stolen from cmd640.c, with
- a few modifications */
+/* The next two functions were stolen from cmd640.c, with a few modifications */
__initfunc(static void write_pcicfg_dword (byte fn, unsigned short reg, long val))
{
@@ -435,244 +354,50 @@ __initfunc(static long read_pcicfg_dword (byte fn, unsigned short reg))
}
/*
- * Search for an (apparently) unused block of I/O space
- * of "size" bytes in length.
- */
-__initfunc(static short find_free_region (unsigned short size))
-{
- unsigned short i, base = 0xe800;
- for (base = 0xe800; base > 0; base -= 0x800) {
- if (!check_region(base,size)) {
- for (i = 0; i < size; i++) {
- if (inb(base+i) != 0xff)
- goto next;
- }
- return base; /* success */
- }
- next:
- }
- return 0; /* failure */
-}
-
-/*
- * Fetch the Bus-Master I/O Base-Address (BMIBA) from PCI space:
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
*/
-__initfunc(static unsigned int ide_get_or_set_bmiba (byte bus, byte fn, const char *name))
+unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) /* __init */
{
- unsigned int bmiba = 0;
- unsigned short base;
- int rc;
-
- if ((rc = pcibios_read_config_dword(bus, fn, 0x20, &bmiba))) {
- printk("%s: failed to read BMIBA\n", name);
- } else if ((bmiba &= 0xfff0) == 0) {
- printk("%s: BMIBA is invalid (0x%04x, BIOS problem)\n", name, bmiba);
- base = find_free_region(16);
- if (base) {
- printk("%s: setting BMIBA to 0x%04x\n", name, base);
- pcibios_write_config_dword(bus, fn, 0x20, base | 1);
- pcibios_read_config_dword(bus, fn, 0x20, &bmiba);
- bmiba &= 0xfff0;
- if (bmiba != base) {
+ unsigned int new, dma_base = 0;
+ byte bus = hwif->pci_bus, fn = hwif->pci_fn;
+
+ if (hwif->mate && hwif->mate->dma_base) {
+ dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+ } else if (pcibios_read_config_dword(bus, fn, 0x20, &dma_base)) {
+ printk("%s: failed to read dma_base\n", name);
+ dma_base = 0;
+ } else if ((dma_base &= ~0xf) == 0 || dma_base == ~0xf) {
+ printk("%s: dma_base is invalid (0x%04x, BIOS problem)\n", name, dma_base);
+ new = ide_find_free_region(16 + extra);
+ hwif->no_autodma = 1; /* default DMA off if we had to configure it here */
+ if (new) {
+ printk("%s: setting dma_base to 0x%04x\n", name, new);
+ new |= 1;
+ (void) pcibios_write_config_dword(bus, fn, 0x20, new);
+ (void) pcibios_read_config_dword(bus, fn, 0x20, &dma_base);
+ if (dma_base != new) {
if (bus == 0) {
printk("%s: operation failed, bypassing BIOS to try again\n", name);
- write_pcicfg_dword(fn, 0x20, base | 1);
- bmiba = read_pcicfg_dword(fn, 0x20) & 0xfff0;
+ write_pcicfg_dword(fn, 0x20, new);
+ dma_base = read_pcicfg_dword(fn, 0x20);
}
- if (bmiba != base) {
+ if (dma_base != new) {
printk("%s: operation failed, DMA disabled\n", name);
- bmiba = 0;
+ dma_base = 0;
}
}
+ dma_base &= ~0xf;
}
}
- return bmiba;
-}
-
-/*
- * Match a PCI IDE port against an entry in ide_hwifs[],
- * based on io_base port if possible.
- */
-__initfunc(ide_hwif_t *ide_match_hwif (unsigned int io_base))
-{
- int h;
- ide_hwif_t *hwif;
-
- /*
- * Look for a hwif with matching io_base specified using
- * parameters to ide_setup().
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
- if (hwif->chipset == ide_generic)
- return hwif; /* a perfect match */
- }
- }
- /*
- * Look for a hwif with matching io_base default value.
- * If chipset is "ide_unknown", then claim that hwif slot.
- * Otherwise, some other chipset has already claimed it.. :(
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- hwif = &ide_hwifs[h];
- if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
- if (hwif->chipset == ide_unknown)
- return hwif; /* match */
- return NULL; /* already claimed */
- }
- }
- /*
- * Okay, there is no hwif matching our io_base,
- * so we'll just claim an unassigned slot.
- * Give preference to claiming ide2/ide3 before ide0/ide1,
- * just in case there's another interface yet-to-be-scanned
- * which uses ports 1f0/170 (the ide0/ide1 defaults).
- */
- for (h = 0; h < MAX_HWIFS; ++h) {
- int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
- hwif = &ide_hwifs[hwifs[h]];
- if (hwif->chipset == ide_unknown)
- return hwif; /* pick an unused entry */
- }
- return NULL;
-}
-
-/*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them. This generic code works for most PCI chipsets.
- *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits. For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
- */
-__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int bmiba, ide_pci_device_t *d))
-{
- unsigned int port, at_least_one_hwif_enabled = 0;
- unsigned short base = 0, ctl = 0;
- byte tmp = 0;
- ide_hwif_t *hwif, *mate = NULL;
-
- for (port = 0; port <= 1; ++port) {
- ide_pci_enablebit_t *e = &(d->enablebits[port]);
- if (e->reg) {
- if (pcibios_read_config_byte(bus, fn, e->reg, &tmp)) {
- printk("%s: unable to read pci reg 0x%x\n", d->name, e->reg);
- } else if ((tmp & e->mask) != e->val)
- continue; /* port not enabled */
- }
- if (pcibios_read_config_word(bus, fn, 0x14+(port*8), &ctl))
- ctl = 0;
- if ((ctl &= 0xfffc) == 0)
- ctl = 0x3f4 ^ (port << 7);
- if (pcibios_read_config_word(bus, fn, 0x10+(port*8), &base))
- base = 0;
- if ((base &= 0xfff8) == 0)
- base = 0x1F0 ^ (port << 7);
- if ((hwif = ide_match_hwif(base)) == NULL) {
- printk("%s: no room in hwif table for port %d\n", d->name, port);
- continue;
- }
- hwif->chipset = ide_pci;
- hwif->pci_port = port;
- if (mate) {
- hwif->mate = mate;
- mate->mate = hwif;
- }
- mate = hwif; /* for next iteration */
- if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
- ide_init_hwif_ports(hwif->io_ports, base, NULL);
- hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
- }
- if (bmiba) {
- if ((inb(bmiba+2) & 0x80)) { /* simplex DMA only? */
- printk("%s: simplex device: DMA disabled\n", d->name);
- } else { /* supports simultaneous DMA on both channels */
- ide_setup_dma(hwif, bmiba + (8 * port), 8);
- }
- }
- if (d->id) { /* For "known" chipsets, allow other irqs during i/o */
- hwif->drives[0].unmask = 1;
- hwif->drives[1].unmask = 1;
- }
- if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */
- d->init_hwif(bus, fn, hwif);
- at_least_one_hwif_enabled = 1;
- }
- if (!at_least_one_hwif_enabled)
- printk("%s: neither IDE port enabled (BIOS)\n", d->name);
-}
-
-/*
- * ide_scan_pci_device() examines all functions of a PCI device,
- * looking for IDE interfaces and/or devices in ide_pci_chipsets[].
- */
-__initfunc(static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn))
-{
- unsigned int devid, ccode;
- unsigned short pcicmd, class;
- ide_pci_device_t *d;
- byte hedt, progif;
-
- if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt))
- hedt = 0;
- do {
- if (pcibios_read_config_dword(bus, fn, 0x00, &devid)
- || devid == 0xffffffff
- || pcibios_read_config_dword(bus, fn, 0x08, &ccode))
- return;
- d = lookup_devid(devid);
- if (d->name == NULL) /* some chips (cmd640, rz1000) are handled elsewhere */
- continue;
- progif = (ccode >> 8) & 0xff;
- class = ccode >> 16;
- if (d->id || class == PCI_CLASS_STORAGE_IDE) {
- if (d->id)
- printk("%s: IDE device on PCI bus %d function %d\n", d->name, bus, fn);
- else
- printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
- d->name, bus, fn, devid & 0xffff, devid >> 16);
- /*
- * See if IDE ports are enabled
- */
- if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)) {
- printk("%s: error accessing PCICMD\n", d->name);
- } else if ((pcicmd & 1) == 0) {
- printk("%s: device disabled (BIOS)\n", d->name);
- } else {
- unsigned int bmiba = 0;
- /*
- * Check for Bus-Master DMA capability
- */
- if (d->id == DEVID_PDC20246 || (class == PCI_CLASS_STORAGE_IDE && (progif & 0x80))) {
- if ((!(pcicmd & 4) || !(bmiba = ide_get_or_set_bmiba(bus, fn, d->name)))) {
- printk("%s: Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, progif=0x%02x, bmiba=0x%04x\n", d->name, pcicmd, progif, bmiba);
- }
- }
- /*
- * Setup the IDE ports
- */
- ide_setup_pci_device(bus, fn, bmiba, d);
- }
- }
- } while (hedt == 0x80 && (++fn & 7));
-}
-
-/*
- * ide_scan_pcibus() gets invoked at boot time from ide.c
- */
-__initfunc(void ide_scan_pcibus (void))
-{
- unsigned int bus, dev;
-
- if (!pcibios_present())
- return;
- for (bus = 0; bus <= 255; ++bus) {
- for (dev = 0; dev <= 31; ++dev) {
- ide_scan_pci_device(bus, dev << 3);
+ if (dma_base) {
+ if (extra) /* PDC20246 */
+ request_region(dma_base+16, extra, name);
+ dma_base += hwif->channel ? 8 : 0;
+ if (inb(dma_base+2) & 0x80) {
+ printk("%s: simplex device: DMA disabled\n", name);
+ dma_base = 0;
}
}
+ return dma_base;
}
diff --git a/drivers/block/ide-floppy.c b/drivers/block/ide-floppy.c
index 2856f330f..5572a07ba 100644
--- a/drivers/block/ide-floppy.c
+++ b/drivers/block/ide-floppy.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-floppy.c Version 0.5 - ALPHA Feb 21, 1997
+ * linux/drivers/block/ide-floppy.c Version 0.8 Feb 21, 1997
*
* Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
*/
@@ -21,8 +21,15 @@
* Use the minimum of the LBA and CHS capacities.
* Avoid hwgroup->rq == NULL on the last irq.
* Fix potential null dereferencing with DEBUG_LOG.
+ * Ver 0.8 Dec 7 97 Increase irq timeout from 10 to 50 seconds.
+ * Add media write-protect detection.
+ * Issue START command only if TEST UNIT READY fails.
+ * Add work-around for IOMEGA ZIP revision 21.D.
+ * Remove idefloppy_get_capabilities().
*/
+#define IDEFLOPPY_VERSION "0.8"
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -31,12 +38,9 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
@@ -60,6 +64,11 @@
#define IDEFLOPPY_DEBUG_BUGS 1
/*
+ * Some drives require a longer irq timeout.
+ */
+#define IDEFLOPPY_WAIT_CMD (5 * WAIT_CMD)
+
+/*
* After each failed packet command we issue a request sense command
* and retry the packet command IDEFLOPPY_MAX_PC_RETRIES times.
*/
@@ -191,6 +200,7 @@ typedef struct {
int blocks, block_size, bs_factor; /* Current format */
idefloppy_capacity_descriptor_t capacity; /* Last format capacity */
idefloppy_flexible_disk_page_t flexible_disk_page; /* Copy of the flexible disk page */
+ int wp; /* Write protect */
unsigned int flags; /* Status/Action flags */
} idefloppy_floppy_t;
@@ -683,13 +693,12 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
+ if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
set_bit (PC_DMA_ERROR, &pc->flags);
} else {
pc->actually_transferred=pc->request_transfer;
idefloppy_update_buffers (drive, pc);
}
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */
#if IDEFLOPPY_DEBUG_LOG
printk (KERN_INFO "ide-floppy: DMA finished\n");
#endif /* IDEFLOPPY_DEBUG_LOG */
@@ -728,8 +737,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
- printk (KERN_ERR "ide-floppy: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
ide_do_reset (drive);
return;
}
@@ -755,7 +763,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
if (temp > pc->buffer_size) {
printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
idefloppy_discard_data (drive,bcount.all);
- ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD);
+ ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD);
return;
}
#if IDEFLOPPY_DEBUG_LOG
@@ -777,7 +785,7 @@ static void idefloppy_pc_intr (ide_drive_t *drive)
pc->actually_transferred+=bcount.all; /* Update the current position */
pc->current_position+=bcount.all;
- ide_set_handler (drive,&idefloppy_pc_intr,WAIT_CMD); /* And set the interrupt handler again */
+ ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD); /* And set the interrupt handler again */
}
static void idefloppy_transfer_pc (ide_drive_t *drive)
@@ -795,7 +803,7 @@ static void idefloppy_transfer_pc (ide_drive_t *drive)
ide_do_reset (drive);
return;
}
- ide_set_handler (drive, &idefloppy_pc_intr, WAIT_CMD); /* Set the interrupt routine */
+ ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD); /* Set the interrupt routine */
atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
}
@@ -843,8 +851,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
- printk (KERN_WARNING "ide-floppy: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -864,7 +871,7 @@ static void idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc)
#endif /* CONFIG_BLK_DEV_IDEDMA */
if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
- ide_set_handler (drive, &idefloppy_transfer_pc, WAIT_CMD);
+ ide_set_handler (drive, &idefloppy_transfer_pc, IDEFLOPPY_WAIT_CMD);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */
} else {
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);
@@ -934,6 +941,12 @@ static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start)
pc->c[4] = start;
}
+static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc)
+{
+ idefloppy_init_pc(pc);
+ pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;
+}
+
static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector)
{
int block = sector / floppy->bs_factor;
@@ -1041,6 +1054,7 @@ static int idefloppy_get_flexible_disk_page (ide_drive_t *drive)
return 1;
}
header = (idefloppy_mode_parameter_header_t *) pc.buffer;
+ floppy->wp = header->wp;
page = (idefloppy_flexible_disk_page_t *) (header + 1);
page->transfer_rate = ntohs (page->transfer_rate);
@@ -1144,13 +1158,21 @@ static int idefloppy_open (struct inode *inode, struct file *filp, ide_drive_t *
MOD_INC_USE_COUNT;
if (drive->usage == 1) {
- idefloppy_create_start_stop_cmd (&pc, 1);
- (void) idefloppy_queue_pc_tail (drive, &pc);
+ idefloppy_create_test_unit_ready_cmd(&pc);
+ if (idefloppy_queue_pc_tail(drive, &pc)) {
+ idefloppy_create_start_stop_cmd (&pc, 1);
+ (void) idefloppy_queue_pc_tail (drive, &pc);
+ }
if (idefloppy_get_capacity (drive)) {
drive->usage--;
MOD_DEC_USE_COUNT;
return -EIO;
}
+ if (floppy->wp && (filp->f_mode & 2)) {
+ drive->usage--;
+ MOD_DEC_USE_COUNT;
+ return -EROFS;
+ }
set_bit (IDEFLOPPY_MEDIA_CHANGED, &floppy->flags);
idefloppy_create_prevent_cmd (&pc, 1);
(void) idefloppy_queue_pc_tail (drive, &pc);
@@ -1243,9 +1265,9 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
default: sprintf (buffer, "Reserved");break;
}
printk (KERN_INFO "Command Packet Size: %s\n", buffer);
- printk (KERN_INFO "Model: %s\n",id->model);
- printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
- printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+ printk (KERN_INFO "Model: %.40s\n",id->model);
+ printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+ printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
printk (KERN_INFO "Write buffer size(?): %d bytes\n",id->buf_size*512);
printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
@@ -1306,51 +1328,13 @@ static int idefloppy_identify_device (ide_drive_t *drive,struct hd_driveid *id)
}
/*
- * idefloppy_get_capabilities asks the floppy about its various
- * parameters.
- */
-static void idefloppy_get_capabilities (ide_drive_t *drive)
-{
- idefloppy_pc_t pc;
- idefloppy_mode_parameter_header_t *header;
- idefloppy_capabilities_page_t *capabilities;
-
- idefloppy_create_mode_sense_cmd (&pc, IDEFLOPPY_CAPABILITIES_PAGE, MODE_SENSE_CURRENT);
- if (idefloppy_queue_pc_tail (drive,&pc)) {
- printk (KERN_ERR "ide-floppy: Can't get drive capabilities\n");
- return;
- }
- header = (idefloppy_mode_parameter_header_t *) pc.buffer;
- capabilities = (idefloppy_capabilities_page_t *) (header + 1);
-
- if (!capabilities->sflp)
- printk (KERN_INFO "%s: Warning - system floppy device bit is not set\n", drive->name);
-
-#if IDEFLOPPY_DEBUG_INFO
- printk (KERN_INFO "Dumping the results of the MODE SENSE packet command\n");
- printk (KERN_INFO "Mode Parameter Header:\n");
- printk (KERN_INFO "Mode Data Length - %d\n",header->mode_data_length);
- printk (KERN_INFO "Medium Type - %d\n",header->medium_type);
- printk (KERN_INFO "WP - %d\n",header->wp);
-
- printk (KERN_INFO "Capabilities Page:\n");
- printk (KERN_INFO "Page code - %d\n",capabilities->page_code);
- printk (KERN_INFO "Page length - %d\n",capabilities->page_length);
- printk (KERN_INFO "PS - %d\n",capabilities->ps);
- printk (KERN_INFO "System Floppy Type device - %s\n",capabilities->sflp ? "Yes":"No");
- printk (KERN_INFO "Supports Reporting progress of Format - %s\n",capabilities->srfp ? "Yes":"No");
- printk (KERN_INFO "Non CD Optical device - %s\n",capabilities->ncd ? "Yes":"No");
- printk (KERN_INFO "Multiple LUN support - %s\n",capabilities->sml ? "Yes":"No");
- printk (KERN_INFO "Total LUN supported - %s\n",capabilities->tlun ? "Yes":"No");
-#endif /* IDEFLOPPY_DEBUG_INFO */
-}
-
-/*
* Driver initialization.
*/
static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
{
struct idefloppy_id_gcw gcw;
+ int major = HWIF(drive)->major, i;
+ int minor = drive->select.b.unit << PARTN_BITS;
*((unsigned short *) &gcw) = drive->id->config;
drive->driver_data = floppy;
@@ -1360,8 +1344,12 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
floppy->pc = floppy->pc_stack;
if (gcw.drq_type == 1)
set_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags);
+ if (strcmp(drive->id->model, "IOMEGA ZIP 100 ATAPI") == 0 &&
+ strcmp(drive->id->fw_rev, "21.D") == 0) {
+ for (i = 0; i < 1 << PARTN_BITS; i++)
+ max_sectors[major][minor + i] = 64;
+ }
- idefloppy_get_capabilities (drive);
(void) idefloppy_get_capacity (drive);
}
@@ -1387,6 +1375,8 @@ static ide_module_t idefloppy_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idefloppy_driver = {
+ "ide-floppy", /* name */
+ IDEFLOPPY_VERSION, /* version */
ide_floppy, /* media */
0, /* busy */
1, /* supports_dma */
@@ -1400,7 +1390,8 @@ static ide_driver_t idefloppy_driver = {
idefloppy_media_change, /* media_change */
NULL, /* pre_reset */
idefloppy_capacity, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
/*
diff --git a/drivers/block/ide-pci.c b/drivers/block/ide-pci.c
new file mode 100644
index 000000000..adcf99525
--- /dev/null
+++ b/drivers/block/ide-pci.c
@@ -0,0 +1,382 @@
+/*
+ * linux/drivers/block/ide-pci.c Version 1.00 December 8, 1997
+ *
+ * Copyright (c) 1995-1998 Mark Lord
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+/*
+ * This modules provides support for automatic detection and
+ * configuration of all PCI IDE interfaces present in a system.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "ide.h"
+
+#define DEVID_PIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1})
+#define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1})
+#define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB})
+#define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1})
+#define DEVID_PDC20246 ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
+#define DEVID_RZ1000 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000})
+#define DEVID_RZ1001 ((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001})
+#define DEVID_CMD640 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640})
+#define DEVID_CMD646 ((ide_pci_devid_t){PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646})
+#define DEVID_SIS5513 ((ide_pci_devid_t){PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513})
+#define DEVID_OPTI621 ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621})
+#define DEVID_OPTI621V ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558})
+#define DEVID_OPTI621X ((ide_pci_devid_t){PCI_VENDOR_ID_OPTI, 0xd568}) /* from datasheets */
+#define DEVID_TRM290 ((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290})
+#define DEVID_NS87410 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410})
+#define DEVID_NS87415 ((ide_pci_devid_t){PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415})
+#define DEVID_HT6565 ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565})
+
+#define IDE_IGNORE ((void *)-1)
+
+#ifdef CONFIG_BLK_DEV_TRM290
+extern void ide_init_trm290(ide_hwif_t *);
+#define INIT_TRM290 &ide_init_trm290
+#else
+#define INIT_TRM290 IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_OPTI621
+extern void ide_init_opti621(ide_hwif_t *);
+#define INIT_OPTI621 &ide_init_opti621
+#else
+#define INIT_OPTI621 NULL
+#endif
+
+#ifdef CONFIG_BLK_DEV_NS87415
+extern void ide_init_ns87415(ide_hwif_t *);
+#define INIT_NS87415 &ide_init_ns87415
+#else
+#define INIT_NS87415 IDE_IGNORE
+#endif
+
+#ifdef CONFIG_BLK_DEV_RZ1000
+extern void ide_init_rz1000(ide_hwif_t *);
+#define INIT_RZ1000 &ide_init_rz1000
+#else
+#define INIT_RZ1000 IDE_IGNORE
+#endif
+
+typedef struct ide_pci_enablebit_s {
+ byte reg; /* byte pci reg holding the enable-bit */
+ byte mask; /* mask to isolate the enable-bit */
+ byte val; /* value of masked reg when "enabled" */
+} ide_pci_enablebit_t;
+
+typedef struct ide_pci_device_s {
+ ide_pci_devid_t devid;
+ const char *name;
+ void (*init_hwif)(ide_hwif_t *hwif);
+ ide_pci_enablebit_t enablebits[2];
+} ide_pci_device_t;
+
+static ide_pci_device_t ide_pci_chipsets[] __initdata = {
+ {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} },
+ {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} },
+ {DEVID_PDC20246,"PDC20246", NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}} },
+ {DEVID_RZ1000, "RZ1000", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_RZ1001, "RZ1001", INIT_RZ1000, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_CMD640, "CMD640", IDE_IGNORE, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_NS87410, "NS87410", NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}} },
+ {DEVID_SIS5513, "SIS5513", NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}} },
+ {DEVID_CMD646, "CMD646", NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}} },
+ {DEVID_HT6565, "HT6565", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_OPTI621, "OPTI621", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
+ {DEVID_OPTI621X,"OPTI621X", INIT_OPTI621, {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
+ {DEVID_TRM290, "TRM290", INIT_TRM290, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {DEVID_NS87415, "NS87415", INIT_NS87415, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+ {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
+
+/*
+ * Search for an (apparently) unused block of I/O space
+ * of "size" bytes in length. Ideally we ought to do a pass
+ * through pcicfg space to eliminate ports already allocated
+ * by the BIOS, to avoid conflicts later in the init cycle,
+ * but we don't. FIXME
+ */
+unsigned int ide_find_free_region (unsigned short size) /* __init */
+{
+ static unsigned short base = 0x5800; /* it works for me */
+ unsigned short i;
+
+ for (; base > 0; base -= 0x200) {
+ if (!check_region(base,size)) {
+ for (i = 0; i < size; i++) {
+ if (inb(base+i) != 0xff)
+ goto next;
+ }
+ return base; /* success */
+ }
+ next:
+ }
+ return 0; /* failure */
+}
+
+/*
+ * Match a PCI IDE port against an entry in ide_hwifs[],
+ * based on io_base port if possible.
+ */
+__initfunc(static ide_hwif_t *ide_match_hwif (unsigned int io_base, const char *name))
+{
+ int h;
+ ide_hwif_t *hwif;
+
+ /*
+ * Look for a hwif with matching io_base specified using
+ * parameters to ide_setup().
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+ if (hwif->chipset == ide_generic)
+ return hwif; /* a perfect match */
+ }
+ }
+ /*
+ * Look for a hwif with matching io_base default value.
+ * If chipset is "ide_unknown", then claim that hwif slot.
+ * Otherwise, some other chipset has already claimed it.. :(
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ hwif = &ide_hwifs[h];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == io_base) {
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* match */
+ printk("%s: port 0x%04x already claimed by %s\n", name, io_base, hwif->name);
+ return NULL; /* already claimed */
+ }
+ }
+ /*
+ * Okay, there is no hwif matching our io_base,
+ * so we'll just claim an unassigned slot.
+ * Give preference to claiming other slots before claiming ide0/ide1,
+ * just in case there's another interface yet-to-be-scanned
+ * which uses ports 1f0/170 (the ide0/ide1 defaults).
+ */
+ for (h = 0; h < MAX_HWIFS; ++h) {
+ int hwifs[] = {2,3,1,0}; /* assign 3rd/4th before 1st/2nd */
+ hwif = &ide_hwifs[hwifs[h]];
+ if (hwif->chipset == ide_unknown)
+ return hwif; /* pick an unused entry */
+ }
+ printk("%s: too many IDE interfaces, no room in table\n", name);
+ return NULL;
+}
+
+__initfunc(static int ide_setup_pci_baseregs (byte bus, byte fn, const char *name))
+{
+ unsigned int base, readback;
+ byte reg, progif = 0;
+
+ /*
+ * Place both IDE interfaces into PCI "native" mode:
+ */
+ if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) {
+ if ((progif & 0xa) != 0xa) {
+ printk("%s: device not capable of full native PCI mode\n", name);
+ return 1;
+ }
+ printk("%s: placing both ports into native PCI mode\n", name);
+ (void) pcibios_write_config_byte(bus, fn, 0x09, progif|5);
+ if (pcibios_read_config_byte(bus, fn, 0x09, &progif) || (progif & 5) != 5) {
+ printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
+ return 1;
+ }
+ }
+ /*
+ * Setup base registers for IDE command/control spaces for each interface:
+ */
+ if (!(base = ide_find_free_region(32)))
+ return 1;
+ for (reg = 0x10; reg <= 0x1c; reg += 4, base += 8) {
+ (void) pcibios_write_config_dword(bus, fn, reg, base|1);
+ if (pcibios_read_config_dword(bus, fn, reg, &readback) || (readback &= ~1) != base) {
+ printk("%s: readback failed for basereg 0x%02x: wrote 0x%04x, read 0x%x04\n", name, reg, base, readback);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ide_setup_pci_device() looks at the primary/secondary interfaces
+ * on a PCI IDE device and, if they are enabled, prepares the IDE driver
+ * for use with them. This generic code works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the
+ * primary/secondary interface "enable/disable" bits. For chipsets that
+ * we "know" about, this information is in the ide_pci_device_t struct;
+ * for all other chipsets, we just assume both interfaces are enabled.
+ */
+__initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int ccode, ide_pci_device_t *d))
+{
+ unsigned int port, at_least_one_hwif_enabled = 0, no_autodma = 0;
+ unsigned short pcicmd = 0;
+ byte tmp = 0, progif = 0, pciirq = 0;
+ ide_hwif_t *hwif, *mate = NULL;
+
+ if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
+ || pcibios_read_config_byte(bus, fn, 0x09, &progif)
+ || pcibios_read_config_byte(bus, fn, 0x3c, &pciirq))
+ {
+ printk("%s: error accessing PCI regs\n", d->name);
+ return;
+ }
+ if (!(pcicmd & 1)) { /* is device disabled? */
+ /*
+ * PnP BIOS was *supposed* to have set this device up for us,
+ * but we can do it ourselves, so long as the BIOS has assigned an IRQ
+ * (or possibly the device is using a "legacy header" for IRQs).
+ * Maybe the user deliberately *disabled* the device,
+ * but we'll eventually ignore it again if no drives respond.
+ */
+ if (ide_setup_pci_baseregs(bus, fn, d->name)
+ || pcibios_write_config_word(bus, fn, 0x04, pcicmd|1)
+ || pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
+ || !(pcicmd & 1))
+ {
+ printk("%s: device disabled (BIOS)\n", d->name);
+ return;
+ }
+ no_autodma = 1; /* default DMA off if we had to configure it here */
+ printk("%s: device enabled (Linux)\n", d->name);
+ }
+ if (!pciirq || pciirq >= NR_IRQS) { /* is pciirq invalid? */
+ if (pciirq || (progif & 0x5)) /* don't complain if using "legacy" mode */
+ printk("%s: BIOS returned %d for IRQ (ignored)\n", d->name, pciirq);
+ pciirq = 0; /* probe for it instead */
+ }
+ /*
+ * Set up the IDE ports
+ */
+ for (port = 0; port <= 1; ++port) {
+ unsigned int base = 0, ctl = 0;
+ ide_pci_enablebit_t *e = &(d->enablebits[port]);
+ if (e->reg && (pcibios_read_config_byte(bus, fn, e->reg, &tmp) || (tmp & e->mask) != e->val))
+ continue; /* port not enabled */
+ if (pcibios_read_config_dword(bus, fn, 0x14+(port*8), &ctl) || (ctl &= ~3) == 0)
+ ctl = port ? 0x374 : 0x3f4; /* use default value */
+ if (pcibios_read_config_dword(bus, fn, 0x10+(port*8), &base) || (base &= ~7) == 0)
+ base = port ? 0x170 : 0x1f0; /* use default value */
+ if ((hwif = ide_match_hwif(base, d->name)) == NULL)
+ continue; /* no room in ide_hwifs[] */
+ if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+ ide_init_hwif_ports(hwif->io_ports, base, NULL);
+ hwif->io_ports[IDE_CONTROL_OFFSET] = ctl + 2;
+ }
+ hwif->chipset = ide_pci;
+ hwif->pci_bus = bus;
+ hwif->pci_fn = fn;
+ hwif->pci_devid = d->devid;
+ hwif->channel = port;
+ hwif->irq = pciirq;
+ if (mate) {
+ hwif->mate = mate;
+ mate->mate = hwif;
+ }
+ if (no_autodma)
+ hwif->no_autodma = 1;
+#ifdef CONFIG_BLK_DEV_IDEDMA
+ if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((ccode >> 16) == PCI_CLASS_STORAGE_IDE && (ccode & 0x8000))) {
+ unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0;
+ unsigned int dma_base = ide_get_or_set_dma_base(hwif, extra, d->name);
+ if (dma_base && !(pcicmd & 4)) {
+ /*
+ * Set up BM-DMA capability (PnP BIOS should have done this)
+ */
+ hwif->no_autodma = 1; /* default DMA off if we had to configure it here */
+ (void) pcibios_write_config_word(bus, fn, 0x04, (pcicmd|4));
+ if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd) || !(pcicmd & 4)) {
+ printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
+ dma_base = 0;
+ }
+ }
+ if (dma_base)
+ ide_setup_dma(hwif, dma_base, 8);
+ else
+ printk("%s: %s Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, ccode=0x%04x, dma_base=0x%04x\n",
+ hwif->name, d->name, pcicmd, ccode, dma_base);
+ }
+#endif /* CONFIG_BLK_DEV_IDEDMA */
+ if (d->init_hwif) /* Call chipset-specific routine for each enabled hwif */
+ d->init_hwif(hwif);
+ mate = hwif;
+ at_least_one_hwif_enabled = 1;
+ }
+ if (!at_least_one_hwif_enabled)
+ printk("%s: neither IDE port enabled (BIOS)\n", d->name);
+}
+
+/*
+ * ide_scan_pci_device() examines all functions of a PCI device,
+ * looking for IDE interfaces and/or devices in ide_pci_chipsets[].
+ * We cannot use pcibios_find_class() cuz it doesn't work in all systems.
+ */
+static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
+{
+ unsigned int ccode;
+ ide_pci_devid_t devid;
+ ide_pci_device_t *d;
+ byte hedt;
+
+ if (pcibios_read_config_byte(bus, fn, 0x0e, &hedt))
+ hedt = 0;
+ do {
+ if (pcibios_read_config_word(bus, fn, 0x00, &devid.vid)
+ || devid.vid == 0xffff
+ || pcibios_read_config_word(bus, fn, 0x02, &devid.did)
+ || IDE_PCI_DEVID_EQ(devid, IDE_PCI_DEVID_NULL)
+ || pcibios_read_config_dword(bus, fn, 0x08, &ccode))
+ return;
+ for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+ if (d->init_hwif == IDE_IGNORE)
+ printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
+ else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(fn & 1))
+ continue; /* OPTI Viper-M uses same devid for functions 0 and 1 */
+ else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (ccode >> 16) == PCI_CLASS_STORAGE_IDE) {
+ if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
+ printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
+ d->name, bus, fn, devid.vid, devid.did);
+ else
+ printk("%s: PCI bus %d function %d\n", d->name, bus, fn);
+ ide_setup_pci_device(bus, fn, ccode, d);
+ }
+ } while (hedt == 0x80 && (++fn & 7));
+}
+
+/*
+ * ide_scan_pcibus() gets invoked at boot time from ide.c
+ *
+ * Loops over all PCI devices on all PCI buses, invoking ide_scan_pci_device().
+ * We cannot use pcibios_find_class() cuz it doesn't work in all systems.
+ */
+void ide_scan_pcibus (void) /* __init */
+{
+ unsigned int bus, dev;
+
+ if (!pcibios_present())
+ return;
+ for (bus = 0; bus <= 255; ++bus) {
+ for (dev = 0; dev < 256; dev += 8) {
+ ide_scan_pci_device(bus, dev);
+ }
+ }
+}
+
diff --git a/drivers/block/ide-probe.c b/drivers/block/ide-probe.c
index 9ae187b7e..8e9336037 100644
--- a/drivers/block/ide-probe.c
+++ b/drivers/block/ide-probe.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/ide-probe.c Version 1.02 Jul 29, 1997
+ * linux/drivers/block/ide-probe.c Version 1.03 Dec 5, 1997
*
- * Copyright (C) 1994-1996 Linus Torvalds & authors (see below)
+ * Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
/*
@@ -10,36 +10,11 @@
*
* This is the IDE probe module, as evolved from hd.c and ide.c.
*
- * From hd.c:
- * |
- * | It traverses the request-list, using interrupts to jump between functions.
- * | As nearly all functions can be called within interrupts, we may not sleep.
- * | Special care is recommended. Have Fun!
- * |
- * | modified by Drew Eckhardt to check nr of hd's from the CMOS.
- * |
- * | Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
- * | in the early extended-partition checks and added DM partitions.
- * |
- * | Early work on error handling by Mika Liljeberg (liljeber@cs.Helsinki.FI).
- * |
- * | IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
- * | and general streamlining by Mark Lord (mlord@pobox.com).
- *
- * October, 1994 -- Complete line-by-line overhaul for linux 1.1.x, by:
- *
- * Mark Lord (mlord@pobox.com) (IDE Perf.Pkg)
- * Delman Lee (delman@mipg.upenn.edu) ("Mr. atdisk2")
- * Scott Snyder (snyder@fnald0.fnal.gov) (ATAPI IDE cd-rom)
- *
- * This was a rewrite of just about everything from hd.c, though some original
- * code is still sprinkled about. Think of it as a major evolution, with
- * inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- *
* Version 1.00 move drive probing code from ide.c to ide-probe.c
* Version 1.01 fix compilation problem for m68k
* Version 1.02 increase WAIT_PIDENTIFY to avoid CD-ROM locking at boot
- * by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Version 1.03 fix for (hwif->chipset == ide_4drives)
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -51,12 +26,9 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
#include <linux/delay.h>
@@ -105,6 +77,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+ id->model[sizeof(id->model)-1] = '\0'; /* we depend on this a lot! */
drive->present = 1;
printk("%s: %s, ", drive->name, id->model);
@@ -115,7 +88,7 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
byte type = (id->config >> 8) & 0x1f;
printk("ATAPI ");
#ifdef CONFIG_BLK_DEV_PDC4030
- if (HWIF(drive)->is_pdc4030_2) {
+ if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
printk(" -- not supported on 2nd Promise port\n");
drive->present = 0;
return;
@@ -160,8 +133,8 @@ static inline void do_identify (ide_drive_t *drive, byte cmd)
*/
static void delay_50ms (void)
{
- unsigned long timer = jiffies + ((HZ + 19)/20) + 1;
- while (timer > jiffies);
+ unsigned long timeout = jiffies + ((HZ + 19)/20) + 1;
+ while (0 < (signed long)(timeout - jiffies));
}
/*
@@ -180,6 +153,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
ide_ioreg_t hd_status;
unsigned long timeout;
unsigned long irqs = 0;
+ byte s, a;
if (!HWIF(drive)->irq) { /* already got an IRQ? */
probe_irq_off(probe_irq_on()); /* clear dangling irqs */
@@ -188,9 +162,11 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
}
delay_50ms(); /* take a deep breath */
- if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) {
- printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name);
- hd_status = IDE_STATUS_REG; /* ancient Seagate drives */
+ a = IN_BYTE(IDE_ALTSTATUS_REG);
+ s = IN_BYTE(IDE_STATUS_REG);
+ if ((a ^ s) & ~INDEX_STAT) {
+ printk("%s: probing with STATUS(0x%02x) instead of ALTSTATUS(0x%02x)\n", drive->name, s, a);
+ hd_status = IDE_STATUS_REG; /* ancient Seagate drives, broken interfaces */
} else
hd_status = IDE_ALTSTATUS_REG; /* use non-intrusive polling */
@@ -208,7 +184,7 @@ static int try_to_identify (ide_drive_t *drive, byte cmd)
timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
timeout += jiffies;
do {
- if (jiffies > timeout) {
+ if (0 < (signed long)(jiffies - timeout)) {
if (irqs)
(void) probe_irq_off(irqs);
return 1; /* drive timed-out */
@@ -285,9 +261,11 @@ static int do_probe (ide_drive_t *drive, byte cmd)
SELECT_DRIVE(hwif,drive);
delay_50ms();
if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) {
- OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */
- delay_50ms(); /* allow BUSY_STAT to assert & clear */
- return 3; /* no i/f present: avoid killing ethernet cards */
+ if (drive->select.b.unit != 0) {
+ SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */
+ delay_50ms(); /* allow BUSY_STAT to assert & clear */
+ }
+ return 3; /* no i/f present: mmm.. this should be a 4 -ml */
}
if (OK_STAT(GET_STAT(),READY_STAT,BUSY_STAT)
@@ -302,7 +280,7 @@ static int do_probe (ide_drive_t *drive, byte cmd)
rc = 3; /* not present or maybe ATAPI */
}
if (drive->select.b.unit != 0) {
- OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */
+ SELECT_DRIVE(hwif,&hwif->drives[0]); /* exit with drive0 selected */
delay_50ms();
(void) GET_STAT(); /* ensure drive irq is clear */
}
@@ -367,7 +345,7 @@ static void probe_cmos_for_drives (ide_hwif_t *hwif)
int unit;
#ifdef CONFIG_BLK_DEV_PDC4030
- if (hwif->is_pdc4030_2)
+ if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
return;
#endif /* CONFIG_BLK_DEV_PDC4030 */
outb_p(0x12,0x70); /* specify CMOS address 0x12 */
@@ -400,12 +378,12 @@ static void probe_hwif (ide_hwif_t *hwif)
return;
if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
probe_cmos_for_drives (hwif);
+ if ((hwif->chipset != ide_4drives || !hwif->mate->present)
#if CONFIG_BLK_DEV_PDC4030
- if (!hwif->is_pdc4030_2 &&
- (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1))) {
-#else
- if (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)) {
+ && (hwif->chipset != ide_pdc4030 || hwif->channel == 0)
#endif /* CONFIG_BLK_DEV_PDC4030 */
+ && (ide_check_region(hwif->io_ports[IDE_DATA_OFFSET],8) || ide_check_region(hwif->io_ports[IDE_CONTROL_OFFSET],1)))
+ {
int msgout = 0;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
@@ -431,8 +409,10 @@ static void probe_hwif (ide_hwif_t *hwif)
(void) probe_for_drive (drive);
if (drive->present && !hwif->present) {
hwif->present = 1;
- ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
- ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+ if (hwif->chipset != ide_4drives || !hwif->mate->present) {
+ ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
+ ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
+ }
}
}
if (hwif->reset) {
@@ -446,7 +426,8 @@ static void probe_hwif (ide_hwif_t *hwif)
do {
delay_50ms();
stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
- } while ((stat & BUSY_STAT) && jiffies < timeout);
+ } while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+
}
restore_flags(flags);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -521,13 +502,11 @@ static int init_irq (ide_hwif_t *hwif)
save_match(hwif, h, &match);
}
if (hwif->serialized) {
- ide_hwif_t *mate = &ide_hwifs[hwif->index^1];
- if (index == mate->index || h->irq == mate->irq)
+ if (hwif->mate && hwif->mate->irq == h->irq)
save_match(hwif, h, &match);
}
if (h->serialized) {
- ide_hwif_t *mate = &ide_hwifs[h->index^1];
- if (hwif->irq == mate->irq)
+ if (h->mate && hwif->irq == h->mate->irq)
save_match(hwif, h, &match);
}
}
@@ -603,7 +582,7 @@ static void init_gendisk (ide_hwif_t *hwif)
{
struct gendisk *gd, **gdp;
unsigned int unit, units, minors;
- int *bs;
+ int *bs, *max_sect;
/* figure out maximum drive number on the interface */
for (units = MAX_DRIVES; units > 0; --units) {
@@ -615,13 +594,17 @@ static void init_gendisk (ide_hwif_t *hwif)
gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
bs = kmalloc (minors*sizeof(int), GFP_KERNEL);
+ max_sect = kmalloc (minors*sizeof(int), GFP_KERNEL);
memset(gd->part, 0, minors * sizeof(struct hd_struct));
/* cdroms and msdos f/s are examples of non-1024 blocksizes */
blksize_size[hwif->major] = bs;
- for (unit = 0; unit < minors; ++unit)
+ max_sectors[hwif->major] = max_sect;
+ for (unit = 0; unit < minors; ++unit) {
*bs++ = BLOCK_SIZE;
+ *max_sect++ = 244;
+ }
for (unit = 0; unit < units; ++unit)
hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
@@ -640,9 +623,8 @@ static void init_gendisk (ide_hwif_t *hwif)
hwif->gd = *gdp = gd; /* link onto tail of list */
}
-static int hwif_init (int h)
+static int hwif_init (ide_hwif_t *hwif)
{
- ide_hwif_t *hwif = &ide_hwifs[h];
void (*rfn)(void);
if (!hwif->present)
@@ -692,7 +674,6 @@ static int hwif_init (int h)
return hwif->present;
}
-int ideprobe_init (void);
static ide_module_t ideprobe_module = {
IDE_PROBE_MODULE,
ideprobe_init,
@@ -713,9 +694,11 @@ int ideprobe_init (void)
* Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
*/
for (index = 0; index < MAX_HWIFS; ++index)
- if (probe[index]) probe_hwif (&ide_hwifs[index]);
+ if (probe[index])
+ probe_hwif(&ide_hwifs[index]);
for (index = 0; index < MAX_HWIFS; ++index)
- if (probe[index]) hwif_init (index);
+ if (probe[index])
+ hwif_init(&ide_hwifs[index]);
ide_register_module(&ideprobe_module);
MOD_DEC_USE_COUNT;
return 0;
diff --git a/drivers/block/ide-proc.c b/drivers/block/ide-proc.c
new file mode 100644
index 000000000..55ad22521
--- /dev/null
+++ b/drivers/block/ide-proc.c
@@ -0,0 +1,505 @@
+/*
+ * linux/drivers/block/proc_ide.c Version 1.01 December 12, 1997
+ *
+ * Copyright (C) 1997-1998 Mark Lord
+ */
+
+/*
+ * This is the /proc/ide/ filesystem implementation.
+ *
+ * The major reason this exists is to provide sufficient access
+ * to driver and config data, such that user-mode programs can
+ * be developed to handle chipset tuning for most PCI interfaces.
+ * This should provide better utilities, and less kernel bloat.
+ *
+ * The entire pci config space for a PCI interface chipset can be
+ * retrieved by just reading it. e.g. "cat /proc/ide3/pci"
+ *
+ * To modify registers, do something like:
+ * echo "40:88" >/proc/ide/ide3/pci
+ * That expression writes 0x88 to pci config register 0x40
+ * on the chip which controls ide3. Multiple tuples can be issued,
+ * and the writes will be completed as an atomic set:
+ * echo "40:88 41:35 42:00 43:00" >/proc/ide/ide3/pci
+ * All numbers must be pairs of ascii hex digits.
+ *
+ * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY
+ * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the
+ * returned data as 256 16-bit words. The "hdparm" utility will
+ * be updated someday soon to use this mechanism.
+ *
+ * Feel free to develop and distribute fancy GUI configuration
+ * utilities for you favorite PCI chipsets. I'll be working on
+ * one for the Promise 20246 someday soon. -ml
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/ctype.h>
+#include "ide.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/*
+ * Standard exit stuff:
+ */
+#define PROC_IDE_READ_RETURN(page,start,off,count,eof,len) \
+{ \
+ len -= off; \
+ if (len < count) { \
+ *eof = 1; \
+ if (len <= 0) \
+ return 0; \
+ } else \
+ len = count; \
+ *start = page + off; \
+ return len; \
+}
+
+
+#ifdef CONFIG_PCI
+
+static int ide_getxdigit(char c)
+{
+ int digit;
+ if (isdigit(c))
+ digit = c - '0';
+ else if (isxdigit(c))
+ digit = tolower(c) - 'a' + 10;
+ else
+ digit = -1;
+ return digit;
+}
+
+
+static int xx_xx_parse_error (const char *start, unsigned long maxlen)
+{
+ char errbuf[7];
+ int i, len = MIN(6, maxlen);
+ for (i = 0; i < len; ++i) {
+ char c = start[i];
+ if (!c || c == '\n')
+ c = '\0';
+ else if (iscntrl(c))
+ c = '?';
+ errbuf[i] = c;
+ }
+ errbuf[i] = '\0';
+ printk("proc_ide: error: expected 'xx:xx', but got '%s'\n", errbuf);
+ return -EINVAL;
+}
+
+static int proc_ide_write_pci
+ (struct file *file, const char *buffer, unsigned long count, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)data;
+ int for_real = 0;
+ unsigned long n, flags;
+ const char *start;
+
+ if (!suser())
+ return -EACCES;
+ /*
+ * Skip over leading whitespace
+ */
+ while (count && isspace(*buffer)) {
+ --count;
+ ++buffer;
+ }
+ /*
+ * Do one full pass to verify all parameters,
+ * then do another to actually write the pci regs.
+ */
+ save_flags(flags);
+ do {
+ const char *p = buffer;
+ n = count;
+ if (for_real) {
+ unsigned long timeout = jiffies + (3 * HZ);
+ cli(); /* ensure all PCI writes are done together */
+ while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) {
+ sti();
+ if (0 < (signed long)(timeout - jiffies)) {
+ printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
+ return -EBUSY;
+ }
+ cli();
+ }
+ }
+ while (n) {
+ int d1, d2, rc;
+ byte reg, val;
+ start = p;
+#if 0
+ printk("loop(%d): n=%ld, input=%.5s\n", for_real, n, p);
+#endif
+ if (n < 5)
+ goto parse_error;
+ if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+ goto parse_error;
+ reg = (d1 << 4) | d2;
+ if (*p++ != ':')
+ goto parse_error;
+ if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+ goto parse_error;
+ val = (d1 << 4) | d2;
+ if (n > 5 && !isspace(*p))
+ goto parse_error;
+ n -= 5;
+ while (n && isspace(*p)) {
+ --n;
+ ++p;
+ }
+ if (for_real) {
+#if 0
+ printk("proc_ide_write_pci: reg=0x%02x, val=0x%02x\n", reg, val);
+#endif
+ rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
+ if (rc) {
+ restore_flags(flags);
+ printk("proc_ide_write_pci: error writing bus %d fn %d reg 0x%02x value 0x%02x\n",
+ hwif->pci_bus, hwif->pci_fn, reg, val);
+ printk("proc_ide_write_pci: %s\n", pcibios_strerror(rc));
+ return -EIO;
+ }
+ }
+ }
+ } while (!for_real++);
+ restore_flags(flags);
+ return count;
+parse_error:
+ restore_flags(flags);
+ return xx_xx_parse_error(start, n);
+}
+
+static int proc_ide_read_pci
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *)data;
+ char *out = page;
+ int len, reg = 0;
+
+ out += sprintf(out, "Bus %d Function %d Vendor %04x Device %04x Channel %d\n",
+ hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
+ do {
+ byte val;
+ int rc = pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, reg, &val);
+ if (rc) {
+ printk("proc_ide_read_pci: error reading bus %d fn %d reg 0x%02x\n",
+ hwif->pci_bus, hwif->pci_fn, reg);
+ printk("proc_ide_read_pci: %s\n", pcibios_strerror(rc));
+ return -EIO;
+ out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
+ } else
+ out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
+ } while (reg < 0x100);
+ len = out - page;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_imodel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+ const char *vids, *dids;
+
+ vids = pci_strvendor(hwif->pci_devid.vid);
+ dids = pci_strdev(hwif->pci_devid.vid, hwif->pci_devid.did);
+ len = sprintf(page,"%s: %s\n", vids ? vids : "(none)", dids ? dids : "(none)");
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+#endif /* CONFIG_PCI */
+
+static int proc_ide_read_type
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+ const char *name;
+
+ switch (hwif->chipset) {
+ case ide_unknown: name = "(none)"; break;
+ case ide_generic: name = "generic"; break;
+ case ide_pci: name = "pci"; break;
+ case ide_cmd640: name = "cmd640"; break;
+ case ide_dtc2278: name = "dtc2278"; break;
+ case ide_ali14xx: name = "ali14xx"; break;
+ case ide_qd6580: name = "qd6580"; break;
+ case ide_umc8672: name = "umc8672"; break;
+ case ide_ht6560b: name = "ht6560b"; break;
+ case ide_pdc4030: name = "pdc4030"; break;
+ case ide_rz1000: name = "rz1000"; break;
+ case ide_trm290: name = "trm290"; break;
+ case ide_4drives: name = "4drives"; break;
+ default: name = "(unknown)"; break;
+ }
+ len = sprintf(page, "%s\n", name);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_mate
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+
+ len = sprintf(page, "%s\n", hwif->mate->name);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_channel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_hwif_t *hwif = (ide_hwif_t *) data;
+ int len;
+
+ page[0] = hwif->channel ? '1' : '0';
+ page[1] = '\n';
+ len = 2;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_get_identify (ide_drive_t *drive, byte *buf)
+{
+ struct request rq;
+ byte *end;
+
+ ide_init_drive_cmd(&rq);
+ rq.buffer = buf;
+ *buf++ = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY;
+ *buf++ = 0;
+ *buf++ = 0;
+ *buf++ = 1;
+ end = buf + (SECTOR_WORDS * 4);
+ while (buf != end)
+ *buf++ = 0; /* pre-zero it, in case identify fails */
+ (void) ide_do_drive_cmd(drive, &rq, ide_wait);
+ return 0;
+}
+
+static int proc_ide_read_identify
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *)data;
+ int len = 0, i = 0;
+
+ if (!proc_ide_get_identify(drive, page)) {
+ unsigned short *val = ((unsigned short *)page) + 2;
+ char *out = ((char *)val) + (SECTOR_WORDS * 4);
+ page = out;
+ do {
+ out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n');
+ val += 1;
+ } while (i < (SECTOR_WORDS * 2));
+ len = out - page;
+ }
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_settings
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len;
+
+ out += sprintf(out,"multcount %i\n", drive->mult_count);
+ out += sprintf(out,"io_32bit %i\n", drive->io_32bit);
+ out += sprintf(out,"unmaskirq %i\n", drive->unmask);
+ out += sprintf(out,"using_dma %i\n", drive->using_dma);
+ out += sprintf(out,"nowerr %i\n", drive->bad_wstat == BAD_R_STAT);
+ out += sprintf(out,"keepsettings %i\n", drive->keep_settings);
+ out += sprintf(out,"nice %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2);
+ len = out - page;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_capacity
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ int len;
+
+ len = sprintf(page,"%li\n", ((ide_driver_t *)drive->driver)->capacity(drive));
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+int proc_ide_read_geometry
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ char *out = page;
+ int len;
+
+ out += sprintf(out,"physical %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
+ out += sprintf(out,"logical %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+ len = out - page;
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_dmodel
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ struct hd_driveid *id = drive->id;
+ int len;
+
+ len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)");
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_driver
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ ide_driver_t *driver = (ide_driver_t *) drive->driver;
+ int len;
+
+ if (!driver)
+ len = sprintf(page, "(none)\n");
+ else
+ len = sprintf(page, "%s version %s\n", driver->name, driver->version);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+static int proc_ide_read_media
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ ide_drive_t *drive = (ide_drive_t *) data;
+ const char *media;
+ int len;
+
+ switch (drive->media) {
+ case ide_disk: media = "disk\n";
+ break;
+ case ide_cdrom: media = "cdrom\n";
+ break;
+ case ide_tape: media = "tape\n";
+ break;
+ case ide_floppy:media = "floppy\n";
+ break;
+ default: media = "UNKNOWN\n";
+ break;
+ }
+ strcpy(page,media);
+ len = strlen(media);
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
+}
+
+
+static ide_proc_entry_t generic_drive_entries[] = {
+ { "capacity", proc_ide_read_capacity, NULL },
+ { "driver", proc_ide_read_driver, NULL },
+ { "identify", proc_ide_read_identify, NULL },
+ { "media", proc_ide_read_media, NULL },
+ { "model", proc_ide_read_dmodel, NULL },
+ { "settings", proc_ide_read_settings, NULL },
+ { NULL, NULL, NULL }
+};
+
+void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+{
+ struct proc_dir_entry *ent;
+
+ if (!drive->proc || !p)
+ return;
+ while (p->name != NULL) {
+ ent = create_proc_entry(p->name, 0, drive->proc);
+ if (!ent) return;
+ ent->data = drive;
+ ent->read_proc = p->read_proc;
+ ent->write_proc = p->write_proc;
+ p++;
+ }
+}
+
+void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p)
+{
+ if (!drive->proc || !p)
+ return;
+ while (p->name != NULL) {
+ remove_proc_entry(p->name, drive->proc);
+ p++;
+ }
+}
+
+static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent)
+{
+ int d;
+
+ for (d = 0; d < MAX_DRIVES; d++) {
+ ide_drive_t *drive = &hwif->drives[d];
+
+ if (!drive->present)
+ continue;
+ drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
+ if (drive->proc)
+ ide_add_proc_entries(drive, generic_drive_entries);
+ }
+}
+
+static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
+{
+ int h;
+ struct proc_dir_entry *hwif_ent, *ent;
+
+ for (h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+
+ if (!hwif->present)
+ continue;
+ hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
+ if (!hwif_ent) return;
+#ifdef CONFIG_PCI
+ if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) {
+ ent = create_proc_entry("pci", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_pci;
+ ent->write_proc = proc_ide_write_pci;;
+
+ ent = create_proc_entry("model", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_imodel;
+ }
+#endif /* CONFIG_PCI */
+ ent = create_proc_entry("channel", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_channel;
+
+ if (hwif->mate && hwif->mate->present) {
+ ent = create_proc_entry("mate", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_mate;
+ }
+
+ ent = create_proc_entry("type", 0, hwif_ent);
+ if (!ent) return;
+ ent->data = hwif;
+ ent->read_proc = proc_ide_read_type;
+
+ create_proc_ide_drives(hwif, hwif_ent);
+ }
+}
+
+void proc_ide_init(void)
+{
+ struct proc_dir_entry *ent;
+ ent = create_proc_entry("ide", S_IFDIR, 0);
+ if (!ent) return;
+ create_proc_ide_interfaces(ent);
+}
diff --git a/drivers/block/ide-tape.c b/drivers/block/ide-tape.c
index e9d7f1433..a30fc9a58 100644
--- a/drivers/block/ide-tape.c
+++ b/drivers/block/ide-tape.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide-tape.c Version 1.11 - BETA Dec 2, 1996
+ * linux/drivers/block/ide-tape.c Version 1.12 Dec 7, 1997
*
* Copyright (C) 1995, 1996 Gadi Oxman <gadio@netvision.net.il>
*
@@ -206,6 +206,11 @@
* Use ide_stall_queue() for DSC overlap.
* Use the maximum speed rather than the current speed
* to compute the request service time.
+ * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data
+ * corruption, which could occur if the total number
+ * of bytes written to the tape was not an integral
+ * number of tape blocks.
+ * Add support for INTERRUPT DRQ devices.
*
* Here are some words from the first releases of hd.c, which are quoted
* in ide.c and apply here as well:
@@ -315,6 +320,8 @@
* sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
*/
+#define IDETAPE_VERSION "1.12"
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -323,12 +330,9 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
@@ -692,6 +696,7 @@ typedef struct {
#define IDETAPE_PIPELINE_ERROR 3 /* Error detected in a pipeline stage */
#define IDETAPE_DETECT_BS 4 /* Attempt to auto-detect the current user block size */
#define IDETAPE_FILEMARK 5 /* Currently on a filemark */
+#define IDETAPE_DRQ_INTERRUPT 6 /* DRQ interrupt device */
/*
* Supported ATAPI tape drives packet commands
@@ -1152,11 +1157,6 @@ static void idetape_postpone_request (ide_drive_t *drive)
*/
static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
{
- unsigned int major = HWIF(drive)->major;
- struct blk_dev_struct *bdev = &blk_dev[major];
-
- bdev->current_request=HWGROUP (drive)->rq; /* Since we may have taken it out */
-
ide_init_drive_cmd (rq);
rq->buffer = (char *) pc;
rq->cmd = IDETAPE_PC_RQ1;
@@ -1542,16 +1542,12 @@ static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
ide_drive_t *drive = hwgroup->drive;
struct request *rq = hwgroup->rq;
idetape_tape_t *tape = drive->driver_data;
- unsigned int major = HWIF(drive)->major;
- struct blk_dev_struct *bdev = &blk_dev[major];
int error;
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "Reached idetape_end_request\n");
#endif /* IDETAPE_DEBUG_LOG */
- bdev->current_request=rq; /* Since we may have taken it out */
-
switch (uptodate) {
case 0: error = IDETAPE_ERROR_GENERAL; break;
case 1: error = 0; break;
@@ -1723,18 +1719,23 @@ static void idetape_pc_intr (ide_drive_t *drive)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
- if (HWIF(drive)->dmaproc(ide_dma_status_bad, drive)) {
- set_bit (PC_DMA_ERROR, &pc->flags);
+ if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
/*
- * We will currently correct the following in
- * idetape_analyze_error.
+ * A DMA error is sometimes expected. For example,
+ * if the tape is crossing a filemark during a
+ * READ command, it will issue an irq and position
+ * itself before the filemark, so that only a partial
+ * data transfer will occur (which causes the DMA
+ * error). In that case, we will later ask the tape
+ * how much bytes of the original request were
+ * actually transferred (we can't receive that
+ * information from the DMA engine on most chipsets).
*/
- pc->actually_transferred=HWIF(drive)->dmaproc(ide_dma_transferred, drive);
+ set_bit (PC_DMA_ERROR, &pc->flags);
} else {
pc->actually_transferred=pc->request_transfer;
idetape_update_buffers (pc);
}
- (void) (HWIF(drive)->dmaproc(ide_dma_abort, drive)); /* End DMA */
#if IDETAPE_DEBUG_LOG
printk (KERN_INFO "ide-tape: DMA finished\n");
#endif /* IDETAPE_DEBUG_LOG */
@@ -1780,7 +1781,7 @@ static void idetape_pc_intr (ide_drive_t *drive)
if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
ide_do_reset (drive);
return;
}
@@ -1873,11 +1874,31 @@ static void idetape_pc_intr (ide_drive_t *drive)
* we will handle the next request.
*
*/
+
+static void idetape_transfer_pc(ide_drive_t *drive)
+{
+ idetape_tape_t *tape = drive->driver_data;
+ idetape_pc_t *pc = tape->pc;
+ idetape_ireason_reg_t ireason;
+
+ if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+ printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
+ return;
+ }
+ ireason.all=IN_BYTE (IDE_IREASON_REG);
+ if (!ireason.b.cod || ireason.b.io) {
+ printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
+ ide_do_reset (drive);
+ return;
+ }
+ ide_set_handler(drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */
+ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
+}
+
static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
{
idetape_tape_t *tape = drive->driver_data;
idetape_bcount_reg_t bcount;
- idetape_ireason_reg_t ireason;
int dma_ok=0;
#if IDETAPE_DEBUG_BUGS
@@ -1918,7 +1939,7 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
@@ -1929,35 +1950,19 @@ static void idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc)
OUT_BYTE (bcount.b.high,IDE_BCOUNTH_REG);
OUT_BYTE (bcount.b.low,IDE_BCOUNTL_REG);
OUT_BYTE (drive->select.all,IDE_SELECT_REG);
-
- ide_set_handler (drive, &idetape_pc_intr, WAIT_CMD); /* Set the interrupt routine */
- OUT_BYTE (WIN_PACKETCMD,IDE_COMMAND_REG); /* Issue the packet command */
-
- if (ide_wait_stat (drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { /* Wait for DRQ to be ready - Assuming Accelerated DRQ */
- /*
- * We currently only support tape drives which report
- * accelerated DRQ assertion. For this case, specs
- * allow up to 50us. We really shouldn't get here.
- *
- * ??? Still needs to think what to do if we reach
- * here anyway.
- */
- printk (KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n");
- return;
- }
- ireason.all=IN_BYTE (IDE_IREASON_REG);
- if (!ireason.b.cod || ireason.b.io) {
- printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
- ide_do_reset (drive);
- return;
- }
- atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */
#ifdef CONFIG_BLK_DEV_IDEDMA
if (dma_ok) { /* Begin DMA, if necessary */
set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
+ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+ ide_set_handler(drive, &idetape_transfer_pc, WAIT_CMD);
+ OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+ } else {
+ OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+ idetape_transfer_pc(drive);
+ }
}
static void idetape_media_access_finished (ide_drive_t *drive)
@@ -2179,7 +2184,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
{
idetape_tape_t *tape = drive->driver_data;
idetape_pc_t *pc;
- struct blk_dev_struct *bdev = &blk_dev[HWIF(drive)->major];
struct request *postponed_rq = tape->postponed_rq;
idetape_status_reg_t status;
@@ -2198,32 +2202,6 @@ static void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned
}
/*
- * This is an important point. We will try to remove our request
- * from the block device request queue while we service the
- * request. Note that the request must be returned to
- * bdev->current_request before the next call to
- * ide_end_drive_cmd or ide_do_drive_cmd to conform with the
- * normal behavior of the IDE driver, which leaves the active
- * request in bdev->current_request during I/O.
- *
- * This will eliminate fragmentation of disk/cdrom requests
- * around a tape request, now that we are using ide_next to
- * insert pending pipeline requests, since we have only one
- * ide-tape.c data request in the device request queue, and
- * thus once removed, ll_rw_blk.c will only see requests from
- * the other device.
- *
- * The potential fragmentation inefficiency was pointed to me
- * by Mark Lord.
- *
- * Uhuh.. the following "fix" is actually not entirely correct.
- * Some day we should probably move to a per device request
- * queue, rather than per interface.
- */
- if (rq->next != NULL && rq->rq_dev != rq->next->rq_dev)
- bdev->current_request=rq->next;
-
- /*
* Retry a failed packet command
*/
if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
@@ -2612,8 +2590,8 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive)
if (tape->merge_stage_size % tape->tape_block_size) {
blocks++;
i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
- memset (tape->merge_stage->bh->b_data + tape->merge_stage->bh->b_count, 0, i);
- tape->merge_stage->bh->b_count += i;
+ memset (tape->bh->b_data + tape->bh->b_count, 0, i);
+ tape->bh->b_count += i;
}
(void) idetape_add_chrdev_write_request (drive, blocks);
tape->merge_stage_size = 0;
@@ -3378,9 +3356,9 @@ static int idetape_identify_device (ide_drive_t *drive,struct hd_driveid *id)
case 1: printk (KERN_INFO "16 bytes\n");break;
default: printk (KERN_INFO "Reserved\n");break;
}
- printk (KERN_INFO "Model: %s\n",id->model);
- printk (KERN_INFO "Firmware Revision: %s\n",id->fw_rev);
- printk (KERN_INFO "Serial Number: %s\n",id->serial_no);
+ printk (KERN_INFO "Model: %.40s\n",id->model);
+ printk (KERN_INFO "Firmware Revision: %.8s\n",id->fw_rev);
+ printk (KERN_INFO "Serial Number: %.20s\n",id->serial_no);
printk (KERN_INFO "Write buffer size: %d bytes\n",id->buf_size*512);
printk (KERN_INFO "DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
printk (KERN_INFO "LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
@@ -3532,6 +3510,7 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
ide_hwif_t *hwif = HWIF(drive);
unsigned long t1, tmid, tn, t;
u16 speed;
+ struct idetape_id_gcw gcw;
drive->driver_data = tape;
drive->ready_stat = 0; /* An ATAPI device ignores DRDY */
@@ -3543,6 +3522,9 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
tape->chrdev_direction = idetape_direction_none;
tape->pc = tape->pc_stack;
tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES;
+ *((unsigned short *) &gcw) = drive->id->config;
+ if (gcw.drq_type == 1)
+ set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags);
idetape_get_mode_sense_results (drive);
@@ -3635,6 +3617,8 @@ static ide_module_t idetape_module = {
* IDE subdriver functions, registered with ide.c
*/
static ide_driver_t idetape_driver = {
+ "ide-tape", /* name */
+ IDETAPE_VERSION, /* version */
ide_tape, /* media */
1, /* busy */
1, /* supports_dma */
@@ -3648,7 +3632,8 @@ static ide_driver_t idetape_driver = {
NULL, /* media_change */
idetape_pre_reset, /* pre_reset */
NULL, /* capacity */
- NULL /* special */
+ NULL, /* special */
+ NULL /* proc */
};
/*
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 50af139cd..3b9a17283 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/ide.c Version 6.05 November 30, 1997
+ * linux/drivers/block/ide.c Version 6.11 December 5, 1997
*
* Copyright (C) 1994-1998 Linus Torvalds & authors (see below)
*/
@@ -95,6 +95,9 @@
* added support for BIOS-enabled UltraDMA
* rename all "promise" things to "pdc4030"
* fix EZ-DRIVE handling on small disks
+ * Version 6.11 fix probe error in ide_scan_devices()
+ * fix ancient "jiffies" polling bugs
+ * mask all hwgroup interrupts on each irq entry
*
* Some additional driver compile-time options are in ide.h
*
@@ -111,18 +114,14 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/major.h>
-#include <linux/blkdev.h>
#include <linux/errno.h>
-#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/malloc.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -312,11 +311,12 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
+ unsigned long flags;
+ save_flags(flags);
cli();
do_vlb_sync(IDE_NSECTOR_REG);
insl(IDE_DATA_REG, buffer, wcount);
- if (drive->unmask)
- sti();
+ restore_flags(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
insl(IDE_DATA_REG, buffer, wcount);
@@ -344,11 +344,12 @@ void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
if (io_32bit) {
#if SUPPORT_VLB_SYNC
if (io_32bit & 2) {
+ unsigned long flags;
+ save_flags(flags);
cli();
do_vlb_sync(IDE_NSECTOR_REG);
outsl(IDE_DATA_REG, buffer, wcount);
- if (drive->unmask)
- sti();
+ restore_flags(flags);
} else
#endif /* SUPPORT_VLB_SYNC */
outsl(IDE_DATA_REG, buffer, wcount);
@@ -469,13 +470,13 @@ static void atapi_reset_pollfunc (ide_drive_t *drive)
ide_hwgroup_t *hwgroup = HWGROUP(drive);
byte stat;
- OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ SELECT_DRIVE(HWIF(drive),drive);
udelay (10);
if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
printk("%s: ATAPI reset complete\n", drive->name);
} else {
- if (jiffies < hwgroup->poll_timeout) {
+ if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);
return; /* continue polling */
}
@@ -500,7 +501,7 @@ static void reset_pollfunc (ide_drive_t *drive)
byte tmp;
if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
- if (jiffies < hwgroup->poll_timeout) {
+ if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
ide_set_handler (drive, &reset_pollfunc, HZ/20);
return; /* continue polling */
}
@@ -542,7 +543,7 @@ static void pre_reset (ide_drive_t *drive)
drive->unmask = 0;
drive->io_32bit = 0;
if (drive->using_dma)
- HWIF(drive)->dmaproc(ide_dma_off, drive);
+ (void) HWIF(drive)->dmaproc(ide_dma_off, drive);
}
if (drive->driver != NULL)
DRIVER(drive)->pre_reset(drive);
@@ -576,7 +577,7 @@ static void do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
pre_reset(drive);
- OUT_BYTE (drive->select.all, IDE_SELECT_REG);
+ SELECT_DRIVE(hwif,drive);
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
@@ -808,7 +809,7 @@ static void drive_cmd_intr (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
byte *args = (byte *) rq->buffer;
- byte stat = GET_STAT();
+ byte test, stat = GET_STAT();
ide_sti();
if ((stat & DRQ_STAT) && args && args[3]) {
@@ -818,7 +819,10 @@ static void drive_cmd_intr (ide_drive_t *drive)
drive->io_32bit = io_32bit;
stat = GET_STAT();
}
- if (OK_STAT(stat,READY_STAT,BAD_STAT))
+ test = stat;
+ if (drive->media == ide_cdrom)
+ test = stat &~BUSY_STAT;
+ if (OK_STAT(test,READY_STAT,BAD_STAT))
ide_end_drive_cmd (drive, stat, GET_ERR());
else
ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */
@@ -870,7 +874,7 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
ide_sti();
timeout += jiffies;
while ((stat = GET_STAT()) & BUSY_STAT) {
- if (jiffies > timeout) {
+ if (0 < (signed long)(jiffies - timeout)) {
restore_flags(flags);
ide_error(drive, "status timeout", stat);
return 1;
@@ -1007,7 +1011,7 @@ repeat:
do {
if (!drive->queue)
continue;
- if (drive->sleep && drive->sleep > jiffies)
+ if (drive->sleep && 0 < (signed long)(drive->sleep - jiffies))
continue;
if (!best) {
best = drive;
@@ -1019,7 +1023,7 @@ repeat:
best = drive;
} while ((drive = drive->next) != hwgroup->drive);
if (best != hwgroup->drive && best && best->service_time > WAIT_MIN_SLEEP && !best->sleep && best->nice1) {
- long t = (signed) (WAKEUP(best) - jiffies);
+ long t = (signed) (WAKEUP(best) - jiffies); /* BUGGY? */
if (t >= WAIT_MIN_SLEEP) {
/*
* We *may* have some time to spare, but first let's see if
@@ -1029,7 +1033,7 @@ repeat:
do {
if (drive->sleep) /* this drive tried to be nice to us */
continue;
- if (WAKEUP(drive) > jiffies - best->service_time && WAKEUP(drive) < jiffies + t) {
+ if (WAKEUP(drive) > (jiffies - best->service_time) && WAKEUP(drive) < (jiffies + t)) { /* BUGGY? */
ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP));
goto repeat;
}
@@ -1057,7 +1061,7 @@ static inline void ide_leave_hwgroup (ide_hwgroup_t *hwgroup)
sleep = drive->sleep;
} while ((drive = drive->next) != hwgroup->drive);
if (sleep) {
- if (sleep < jiffies + WAIT_MIN_SLEEP)
+ if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
sleep = jiffies + WAIT_MIN_SLEEP;
hwgroup->timer.expires = sleep;
add_timer(&hwgroup->timer);
@@ -1189,7 +1193,7 @@ void ide_timer_expiry (unsigned long data)
handler(drive);
else { /* abort the operation */
if (hwgroup->hwif->dmaproc)
- (void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);
+ (void) hwgroup->hwif->dmaproc (ide_dma_end, drive);
ide_error(drive, "irq timeout", GET_STAT());
}
cli();
@@ -1229,7 +1233,6 @@ void ide_timer_expiry (unsigned long data)
static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
{
byte stat;
- unsigned int unit;
ide_hwif_t *hwif = hwgroup->hwif;
/*
@@ -1237,27 +1240,18 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
*/
do {
if (hwif->irq == irq) {
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t *drive = &hwif->drives[unit];
- if (!drive->present)
- continue;
- SELECT_DRIVE(hwif,drive);
- udelay(100); /* Ugly, but wait_stat() may not be safe here */
- if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {
- /* Try to not flood the console with msgs */
- static unsigned long last_msgtime = 0;
- if ((last_msgtime + (HZ/2)) < jiffies) {
- last_msgtime = jiffies;
- (void) ide_dump_status(drive, "unexpected_intr", stat);
- }
+ stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+ if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {
+ /* Try to not flood the console with msgs */
+ static unsigned long last_msgtime = 0;
+ if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
+ last_msgtime = jiffies;
+ printk("%s%s: unexpected interrupt, status=0x%02x\n",
+ hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat);
}
- if ((stat & DRQ_STAT))
- try_to_flush_leftover_data(drive);
}
}
} while ((hwif = hwif->next) != hwgroup->hwif);
- SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */
- udelay(100); /* Ugly, but wait_stat() may not be safe here */
}
/*
@@ -1266,14 +1260,28 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
{
ide_hwgroup_t *hwgroup = dev_id;
+ ide_hwif_t *hwif = hwgroup->hwif;
ide_handler_t *handler;
- if (!ide_ack_intr (hwgroup->hwif->io_ports[IDE_STATUS_OFFSET],
- hwgroup->hwif->io_ports[IDE_IRQ_OFFSET]))
+ if (!ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]))
return;
-
- if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {
+ do {
+ if (hwif->irq != irq) disable_irq(hwif->irq);
+ } while ((hwif = hwif->next) != hwgroup->hwif);
+ if (irq == hwif->irq && (handler = hwgroup->handler) != NULL) {
ide_drive_t *drive = hwgroup->drive;
+#if 1 /* temporary, remove later -- FIXME */
+ {
+ struct request *rq = hwgroup->rq;
+ if (rq != NULL
+ &&( MAJOR(rq->rq_dev) != HWIF(drive)->major
+ || (MINOR(rq->rq_dev) >> PARTN_BITS) != drive->select.b.unit))
+ {
+ printk("ide_intr: got IRQ from wrong device: email mlord@pobox.com!!\n");
+ return;
+ }
+ }
+#endif /* temporary */
hwgroup->handler = NULL;
del_timer(&(hwgroup->timer));
if (drive->unmask)
@@ -1289,6 +1297,10 @@ void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
unexpected_intr(irq, hwgroup);
}
cli();
+ hwif = hwgroup->hwif;
+ do {
+ if (hwif->irq != irq) enable_irq(hwif->irq);
+ } while ((hwif = hwif->next) != hwgroup->hwif);
}
/*
@@ -1627,6 +1639,7 @@ void ide_unregister (unsigned int index)
*/
unregister_blkdev(hwif->major, hwif->name);
kfree(blksize_size[hwif->major]);
+ kfree(max_sectors[hwif->major]);
blk_dev[hwif->major].request_fn = NULL;
blk_dev[hwif->major].data = NULL;
blk_dev[hwif->major].queue = NULL;
@@ -1686,13 +1699,15 @@ found:
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- int err;
+ int err, major, minor;
ide_drive_t *drive;
unsigned long flags;
struct request rq;
+ kdev_t dev;
- if (!inode || !(inode->i_rdev))
+ if (!inode || !(dev = inode->i_rdev))
return -EINVAL;
+ major = MAJOR(dev); minor = MINOR(dev);
if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENODEV;
ide_init_drive_cmd (&rq);
@@ -1726,6 +1741,23 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
+ case BLKFRASET:
+ if (!suser()) return -EACCES;
+ max_readahead[major][minor] = arg;
+ return 0;
+
+ case BLKFRAGET:
+ return put_user(max_readahead[major][minor], (long *) arg);
+
+ case BLKSECTSET:
+ if (!suser()) return -EACCES;
+ if (!arg || arg > 0xff) return -EINVAL;
+ max_sectors[major][minor] = arg;
+ return 0;
+
+ case BLKSECTGET:
+ return put_user(max_sectors[major][minor], (long *) arg);
+
case BLKRRPART: /* Re-read partition tables */
if (!suser()) return -EACCES;
return ide_revalidate_disk(inode->i_rdev);
@@ -2074,6 +2106,9 @@ __initfunc(static int match_parm (char *s, const char *keywords[], int vals[], i
* This is the default for most chipsets,
* except the cmd640.
* "idex=serialize" : do not overlap operations on idex and ide(x^1)
+ * "idex=four" : four drives on idex and ide(x^1) share same ports
+ * "idex=reset" : reset interface before first use
+ * "idex=nodma" : do not enable DMA by default on either drive
*
* The following are valid ONLY on ide0,
* and the defaults for the base,ctl ports must not be altered.
@@ -2175,8 +2210,8 @@ __initfunc(void ide_setup (char *s))
/*
* Be VERY CAREFUL changing this: note hardcoded indexes below
*/
- const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "qd6580",
- "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "four", "reset", NULL};
+ const char *ide_words[] = {"noprobe", "serialize", "autotune", "noautotune", "reset", "nodma", "four",
+ "qd6580", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL};
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
i = match_parm(&s[4], ide_words, vals, 3);
@@ -2184,42 +2219,19 @@ __initfunc(void ide_setup (char *s))
/*
* Cryptic check to ensure chipset not already set for hwif:
*/
- if (i > 0 || (i <= -5 && i != -13)) {
+ if (i > 0 || i <= -7) { /* is parameter a chipset name? */
if (hwif->chipset != ide_unknown)
- goto bad_option;
- if (i <= -5) {
- if (ide_hwifs[1].chipset != ide_unknown)
- goto bad_option;
- /*
- * Interface keywords work only for ide0:
- */
- if (hw != 0)
- goto bad_hwif;
- printk("\n");
- }
+ goto bad_option; /* chipset already specified */
+ if (i != -7 && hw != 0)
+ goto bad_hwif; /* chipset drivers are for "ide0=" only */
+ if (ide_hwifs[hw^1].chipset != ide_unknown)
+ goto bad_option; /* chipset for 2nd port already specified */
+ printk("\n");
}
switch (i) {
- case -13: /* "reset" */
- hwif->reset = 1;
- goto done;
-#ifdef CONFIG_BLK_DEV_4DRIVES
- case -12: /* "four" drives on one set of ports */
- {
- ide_hwif_t *mate = &ide_hwifs[hw^1];
- mate->mate = hwif;
- hwif->mate = mate;
- hwif->chipset = mate->chipset = ide_4drives;
- hwif->serialized = mate->serialized = 1;
- mate->drives[0].select.all ^= 0x20;
- mate->drives[1].select.all ^= 0x20;
- memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
- mate->irq = hwif->irq;
- goto done;
- }
-#endif /* CONFIG_BLK_DEV_4DRIVES */
#ifdef CONFIG_BLK_DEV_PDC4030
- case -11: /* "dc4030" */
+ case -14: /* "dc4030" */
{
extern void setup_pdc4030(ide_hwif_t *);
setup_pdc4030(hwif);
@@ -2227,7 +2239,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_PDC4030 */
#ifdef CONFIG_BLK_DEV_ALI14XX
- case -10: /* "ali14xx" */
+ case -13: /* "ali14xx" */
{
extern void init_ali14xx (void);
init_ali14xx();
@@ -2235,7 +2247,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_ALI14XX */
#ifdef CONFIG_BLK_DEV_UMC8672
- case -9: /* "umc8672" */
+ case -12: /* "umc8672" */
{
extern void init_umc8672 (void);
init_umc8672();
@@ -2243,7 +2255,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_UMC8672 */
#ifdef CONFIG_BLK_DEV_DTC2278
- case -8: /* "dtc2278" */
+ case -11: /* "dtc2278" */
{
extern void init_dtc2278 (void);
init_dtc2278();
@@ -2251,7 +2263,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_DTC2278 */
#ifdef CONFIG_BLK_DEV_CMD640
- case -7: /* "cmd640_vlb" */
+ case -10: /* "cmd640_vlb" */
{
extern int cmd640_vlb; /* flag for cmd640.c */
cmd640_vlb = 1;
@@ -2259,7 +2271,7 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_CMD640 */
#ifdef CONFIG_BLK_DEV_HT6560B
- case -6: /* "ht6560b" */
+ case -9: /* "ht6560b" */
{
extern void init_ht6560b (void);
init_ht6560b();
@@ -2267,13 +2279,31 @@ __initfunc(void ide_setup (char *s))
}
#endif /* CONFIG_BLK_DEV_HT6560B */
#if CONFIG_BLK_DEV_QD6580
- case -5: /* "qd6580" (has secondary i/f) */
+ case -8: /* "qd6580" */
{
extern void init_qd6580 (void);
init_qd6580();
goto done;
}
#endif /* CONFIG_BLK_DEV_QD6580 */
+#ifdef CONFIG_BLK_DEV_4DRIVES
+ case -7: /* "four" drives on one set of ports */
+ {
+ ide_hwif_t *mate = &ide_hwifs[hw^1];
+ mate->drives[0].select.all ^= 0x20;
+ mate->drives[1].select.all ^= 0x20;
+ hwif->chipset = mate->chipset = ide_4drives;
+ mate->irq = hwif->irq;
+ memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports));
+ goto do_serialize;
+ }
+#endif /* CONFIG_BLK_DEV_4DRIVES */
+ case -6: /* nodma */
+ hwif->no_autodma = 1;
+ goto done;
+ case -5: /* "reset" */
+ hwif->reset = 1;
+ goto done;
case -4: /* "noautotune" */
hwif->drives[0].autotune = 2;
hwif->drives[1].autotune = 2;
@@ -2284,8 +2314,9 @@ __initfunc(void ide_setup (char *s))
goto done;
case -2: /* "serialize" */
do_serialize:
- ide_hwifs[hw].serialized = 1; /* serialize */
- ide_hwifs[hw^1].serialized = 1; /* with mate */
+ hwif->mate = &ide_hwifs[hw^1];
+ hwif->mate->mate = hwif;
+ hwif->serialized = hwif->mate->serialized = 1;
goto done;
case -1: /* "noprobe" */
@@ -2395,44 +2426,37 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, const char *msg)
/*
* probe_for_hwifs() finds/initializes "known" IDE interfaces
- *
- * This routine should ideally be using pcibios_find_class() to find all
- * PCI IDE interfaces, but that function causes some systems to "go weird".
*/
__initfunc(static void probe_for_hwifs (void))
{
#ifdef CONFIG_PCI
- /*
- * Find/initialize PCI IDE interfaces
- */
if (pcibios_present())
{
-#ifdef CONFIG_BLK_DEV_IDEDMA
- {
- extern void ide_scan_pcibus(void);
- ide_scan_pcibus();
- }
-#endif
+#ifdef CONFIG_BLK_DEV_IDEPCI
+ ide_scan_pcibus();
+#else
#ifdef CONFIG_BLK_DEV_RZ1000
{
extern void ide_probe_for_rz100x(void);
ide_probe_for_rz100x();
}
-#endif
+#endif /* CONFIG_BLK_DEV_RZ1000 */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_PCI */
+
#ifdef CONFIG_BLK_DEV_CMD640
{
extern void ide_probe_for_cmd640x(void);
ide_probe_for_cmd640x();
}
-#endif
+#endif /* CONFIG_BLK_DEV_CMD640 */
#ifdef CONFIG_BLK_DEV_PDC4030
{
extern int init_pdc4030(void);
(void) init_pdc4030();
}
-#endif
+#endif /* CONFIG_BLK_DEV_PDC4030 */
}
__initfunc(void ide_init_builtin_drivers (void))
@@ -2460,6 +2484,10 @@ __initfunc(void ide_init_builtin_drivers (void))
#endif /* __mc68000__ */
#endif /* CONFIG_BLK_DEV_IDE */
+#ifdef CONFIG_PROC_FS
+ proc_ide_init();
+#endif
+
/*
* Attempt to match drivers for the available drives
*/
@@ -2552,18 +2580,19 @@ static void setup_driver_defaults (ide_drive_t *drive)
ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n)
{
unsigned int unit, index, i;
- ide_drive_t *drive;
for (index = 0; index < MAX_HWIFS; ++index)
if (ide_hwifs[index].present) goto search;
ide_init_module(IDE_PROBE_MODULE);
search:
for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- drive = &ide_hwifs[index].drives[unit];
- if (drive->present && drive->media == media &&
- drive->driver == driver && ++i > n)
- return drive;
+ ide_hwif_t *hwif = &ide_hwifs[index];
+ if (hwif->present) {
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+ return drive;
+ }
}
}
return NULL;
@@ -2590,6 +2619,7 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
drive->nice1 = 1;
}
drive->revalidate = 1;
+ ide_add_proc_entries(drive, driver->proc);
return 0;
}
@@ -2603,6 +2633,7 @@ int ide_unregister_subdriver (ide_drive_t *drive)
restore_flags(flags);
return 1;
}
+ ide_remove_proc_entries(drive, DRIVER(drive)->proc);
drive->driver = NULL;
restore_flags(flags);
return 0;
@@ -2694,6 +2725,9 @@ EXPORT_SYMBOL(ide_end_request);
EXPORT_SYMBOL(ide_revalidate_disk);
EXPORT_SYMBOL(ide_cmd);
EXPORT_SYMBOL(ide_stall_queue);
+EXPORT_SYMBOL(ide_add_proc_entries);
+EXPORT_SYMBOL(ide_remove_proc_entries);
+EXPORT_SYMBOL(proc_ide_read_geometry);
EXPORT_SYMBOL(ide_register);
EXPORT_SYMBOL(ide_unregister);
diff --git a/drivers/block/ide.h b/drivers/block/ide.h
index dd3549ac9..dfcb80fa5 100644
--- a/drivers/block/ide.h
+++ b/drivers/block/ide.h
@@ -7,10 +7,15 @@
*/
#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/hdreg.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
#include <asm/ide.h>
/*
- * This is the multiple IDE interface driver, as evolved from hd.c.
+ * This is the multiple IDE interface driver, as evolved from hd.c.
* It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec.
*
@@ -22,7 +27,7 @@
/******************************************************************************
* IDE driver configuration options (play with these as desired):
- *
+ *
* REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
*/
#undef REALLY_FAST_IO /* define if ide ports are perfect */
@@ -164,18 +169,13 @@ typedef unsigned char byte; /* used everywhere */
#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */
#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */
-#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290)
#define SELECT_DRIVE(hwif,drive) \
{ \
if (hwif->selectproc) \
hwif->selectproc(drive); \
- else \
- OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+ OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
}
-#else
-#define SELECT_DRIVE(hwif,drive) OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
-#endif /* CONFIG_BLK_DEV_HT6560B || CONFIG_BLK_DEV_PDC4030 */
-
+
/*
* Now for the data we need to maintain per-drive: ide_drive_t
*/
@@ -248,7 +248,7 @@ typedef struct ide_drive_s {
byte bios_sect __attribute__ ((aligned (8))); /* BIOS/fdisk/LILO sectors per track */
unsigned short bios_cyl; /* BIOS/fdisk/LILO number of cyls */
unsigned short cyl; /* "real" number of cyls */
- unsigned int timing_data; /* for use by tuneproc()'s */
+ unsigned int drive_data; /* for use by tuneproc/selectproc as needed */
void *hwif; /* actually (ide_hwif_t *) */
struct wait_queue *wqueue; /* used to wait for drive in open() */
struct hd_driveid *id; /* drive model identification info */
@@ -256,6 +256,7 @@ typedef struct ide_drive_s {
char name[4]; /* drive name, such as "hda" */
void *driver; /* (ide_driver_t *) */
void *driver_data; /* extra driver data */
+ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
} ide_drive_t;
/*
@@ -269,12 +270,9 @@ typedef struct ide_drive_s {
* Returns 1 if DMA read/write could not be started, in which case the caller
* should either try again later, or revert to PIO for the current request.
*/
-typedef enum { ide_dma_read = 0, ide_dma_write = 1,
- ide_dma_abort = 2, ide_dma_check = 3,
- ide_dma_status_bad = 4, ide_dma_transferred = 5,
- ide_dma_begin = 6, ide_dma_on = 7,
- ide_dma_off = 8, ide_dma_off_quietly = 9 }
- ide_dma_action_t;
+typedef enum { ide_dma_read, ide_dma_write, ide_dma_begin, ide_dma_end,
+ ide_dma_check, ide_dma_on, ide_dma_off, ide_dma_off_quietly
+ } ide_dma_action_t;
typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
@@ -293,7 +291,7 @@ typedef int (ide_dmaproc_t)(ide_dma_action_t, ide_drive_t *);
typedef void (ide_tuneproc_t)(ide_drive_t *, byte);
/*
- * This is used to provide HT6560B & PDC4030 & TRM290 interface support.
+ * This is used to provide support for strange interfaces
*/
typedef void (ide_selectproc_t) (ide_drive_t *);
@@ -305,8 +303,16 @@ typedef enum { ide_unknown, ide_generic, ide_pci,
ide_cmd640, ide_dtc2278, ide_ali14xx,
ide_qd6580, ide_umc8672, ide_ht6560b,
ide_pdc4030, ide_rz1000, ide_trm290,
- ide_4drives }
- hwif_chipset_t;
+ ide_4drives
+ } hwif_chipset_t;
+
+typedef struct ide_pci_devid_s {
+ unsigned short vid;
+ unsigned short did;
+} ide_pci_devid_t;
+
+#define IDE_PCI_DEVID_NULL ((ide_pci_devid_t){0,0})
+#define IDE_PCI_DEVID_EQ(a,b) (a.vid == b.vid && a.did == b.did)
typedef struct hwif_s {
struct hwif_s *next; /* for linked-list in ide_hwgroup_t */
@@ -315,13 +321,14 @@ typedef struct hwif_s {
ide_drive_t drives[MAX_DRIVES]; /* drive info */
struct gendisk *gd; /* gendisk structure */
ide_tuneproc_t *tuneproc; /* routine to tune PIO mode for drives */
-#if defined(CONFIG_BLK_DEV_HT6560B) || defined(CONFIG_BLK_DEV_PDC4030) || defined(CONFIG_BLK_DEV_TRM290)
ide_selectproc_t *selectproc; /* tweaks hardware to select drive */
-#endif
ide_dmaproc_t *dmaproc; /* dma read/write/abort routine */
unsigned long *dmatable; /* dma physical region descriptor table */
struct hwif_s *mate; /* other hwif from same PCI chip */
- unsigned short dma_base; /* base addr for dma ports (triton) */
+ unsigned int dma_base; /* base addr for dma ports */
+ unsigned int config_data; /* for use by chipset-specific code */
+ unsigned int select_data; /* for use by chipset-specific code */
+ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
int irq; /* our irq number */
byte major; /* our major number */
char name[6]; /* name of interface, eg. "ide0" */
@@ -331,11 +338,12 @@ typedef struct hwif_s {
unsigned present : 1; /* this interface exists */
unsigned serialized : 1; /* serialized operation with mate hwif */
unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */
-#ifdef CONFIG_BLK_DEV_PDC4030
- unsigned is_pdc4030_2: 1;/* 2nd i/f on pdc4030 */
-#endif /* CONFIG_BLK_DEV_PDC4030 */
- unsigned reset : 1; /* reset after probe */
- unsigned pci_port : 1; /* for dual-port chips: 0=primary, 1=secondary */
+ unsigned reset : 1; /* reset after probe */
+ unsigned no_autodma : 1; /* don't automatically enable DMA at boot */
+ byte channel; /* for dual-port chips: 0=primary, 1=secondary */
+ byte pci_bus; /* for pci chipsets */
+ byte pci_fn; /* for pci chipsets */
+ ide_pci_devid_t pci_devid; /* for pci chipsets: {VID,DID} */
#if (DISK_RECOVERY_TIME > 0)
unsigned long last_time; /* time when previous rq was done */
#endif
@@ -358,6 +366,20 @@ typedef struct hwgroup_s {
} ide_hwgroup_t;
/*
+ * /proc/ide interface
+ */
+typedef struct {
+ char *name;
+ read_proc_t *read_proc;
+ write_proc_t *write_proc;
+} ide_proc_entry_t;
+
+void proc_ide_init(void);
+void ide_add_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+void ide_remove_proc_entries(ide_drive_t *drive, ide_proc_entry_t *p);
+read_proc_t proc_ide_read_geometry;
+
+/*
* Subdrivers support.
*/
#define IDE_SUBDRIVER_VERSION 1
@@ -374,6 +396,8 @@ typedef unsigned long (ide_capacity_proc)(ide_drive_t *);
typedef void (ide_special_proc)(ide_drive_t *);
typedef struct ide_driver_s {
+ const char *name;
+ const char *version;
byte media;
unsigned busy : 1;
unsigned supports_dma : 1;
@@ -388,6 +412,7 @@ typedef struct ide_driver_s {
ide_pre_reset_proc *pre_reset;
ide_capacity_proc *capacity;
ide_special_proc *special;
+ ide_proc_entry_t *proc;
} ide_driver_t;
#define DRIVER(drive) ((ide_driver_t *)((drive)->driver))
@@ -410,7 +435,7 @@ typedef struct ide_module_s {
/*
* ide_hwifs[] is the master data structure used to keep track
* of just about everything in ide.c. Whenever possible, routines
- * should be using pointers to a drive (ide_drive_t *) or
+ * should be using pointers to a drive (ide_drive_t *) or
* pointers to a hwif (ide_hwif_t *), rather than indexing this
* structure directly (the allocation/layout may change!).
*
@@ -533,7 +558,7 @@ typedef enum
* 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
+ * This is VERY DANGEROUS, and is intended for careful use by the
* ATAPI tape/cdrom driver code.
*
* If action is ide_end, then the rq is queued at the end of the
@@ -542,7 +567,7 @@ typedef enum
* use by the ATAPI tape/cdrom driver code.
*/
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
-
+
/*
* Clean up after success/failure of an explicit drive cmd.
* stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD).
@@ -617,10 +642,16 @@ ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n);
int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
int ide_unregister_subdriver (ide_drive_t *drive);
+#ifdef CONFIG_BLK_DEV_IDEPCI
+unsigned int ide_find_free_region (unsigned short size) __init;
+void ide_scan_pcibus (void) __init;
+#endif
#ifdef CONFIG_BLK_DEV_IDEDMA
int ide_build_dmatable (ide_drive_t *drive);
+void ide_dma_intr (ide_drive_t *drive);
int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned short dmabase, unsigned int num_ports);
+void ide_setup_dma (ide_hwif_t *hwif, unsigned int dmabase, unsigned int num_ports) __init;
+unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
#endif
#ifdef CONFIG_BLK_DEV_IDE
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 925423581..d4a83f9a1 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -87,6 +87,18 @@ int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
*/
int * max_readahead[MAX_BLKDEV] = { NULL, NULL, };
+/*
+ * Max number of sectors per request
+ */
+int * max_sectors[MAX_BLKDEV] = { NULL, NULL, };
+
+static inline int get_max_sectors(kdev_t dev)
+{
+ if (!max_sectors[MAJOR(dev)])
+ return 244; /* 254? */
+ return max_sectors[MAJOR(dev)][MINOR(dev)];
+}
+
static inline struct request **get_queue(kdev_t dev)
{
int major = MAJOR(dev);
@@ -300,9 +312,7 @@ void add_request(struct blk_dev_struct * dev, struct request * req)
sti();
}
-#define MAX_SECTORS 244
-
-static inline void attempt_merge (struct request *req)
+static inline void attempt_merge (struct request *req, int max_sectors)
{
struct request *next = req->next;
@@ -310,7 +320,7 @@ static inline void attempt_merge (struct request *req)
return;
if (req->sector + req->nr_sectors != next->sector)
return;
- if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors >= MAX_SECTORS)
+ if (next->sem || req->cmd != next->cmd || req->rq_dev != next->rq_dev || req->nr_sectors + next->nr_sectors > max_sectors)
return;
req->bhtail->b_reqnext = next->bh;
req->bhtail = next->bhtail;
@@ -324,7 +334,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
{
unsigned int sector, count;
struct request * req;
- int rw_ahead, max_req;
+ int rw_ahead, max_req, max_sectors;
count = bh->b_size >> 9;
sector = bh->b_rsector;
@@ -391,6 +401,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
/*
* Try to coalesce the new request with old requests
*/
+ max_sectors = get_max_sectors(bh->b_rdev);
cli();
req = *get_queue(bh->b_rdev);
if (!req) {
@@ -428,7 +439,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
continue;
if (req->cmd != rw)
continue;
- if (req->nr_sectors >= MAX_SECTORS)
+ if (req->nr_sectors + count > max_sectors)
continue;
if (req->rq_dev != bh->b_rdev)
continue;
@@ -438,7 +449,7 @@ void make_request(int major,int rw, struct buffer_head * bh)
req->bhtail = bh;
req->nr_sectors += count;
/* Can we now merge this req with the next? */
- attempt_merge(req);
+ attempt_merge(req, max_sectors);
/* or to the beginning? */
} else if (req->sector - count == sector) {
bh->b_reqnext = req->bh;
@@ -684,6 +695,7 @@ __initfunc(int blk_dev_init(void))
}
memset(ro_bits,0,sizeof(ro_bits));
memset(max_readahead, 0, sizeof(max_readahead));
+ memset(max_sectors, 0, sizeof(max_sectors));
#ifdef CONFIG_AMIGA_Z2RAM
z2_init();
#endif
diff --git a/drivers/block/ns87415.c b/drivers/block/ns87415.c
new file mode 100644
index 000000000..62ae86f61
--- /dev/null
+++ b/drivers/block/ns87415.c
@@ -0,0 +1,228 @@
+/*
+ * linux/drivers/block/ns87415.c Version 1.00 December 7, 1997
+ *
+ * Copyright (C) 1997-1998 Mark Lord
+ *
+ * Inspired by an earlier effort from David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/io.h>
+#include "ide.h"
+
+
+#undef INCLUDE_OBSOLETE_NS87514_STUFF /* define this if you absolutely *need* the timings stuff */
+
+
+#ifdef INCLUDE_OBSOLETE_NS87514_STUFF
+/*
+ * This part adapted from code from David S. Miller (davem@caipfs.rutgers.edu)
+ * which was in turn adapted from code from Mark Lord.
+ *
+ * Here as a temporary measure only. Will be removed once /proc/ide/ is working.
+ */
+#include "ide_modes.h"
+
+static void ns87415_program_modes(ide_drive_t *drive, byte active_count, byte recovery_count)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ byte cfg_reg, regval;
+
+ cfg_reg = (0x44 + (8 * HWIF(drive)->channel) + (4 * drive->select.b.unit));
+
+ /* set identical PIO timings for read/write */
+ regval = (17 - active_count) | ((16 - recovery_count) << 4);
+ pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg, regval);
+ pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, cfg_reg + 1, regval);
+}
+
+static void set_ide_modes(ide_drive_t *drive, ide_pio_data_t *d, int bus_speed)
+{
+ int setup_time, active_time, cycle_time = d->cycle_time;
+ byte setup_count, active_count, pio_mode = d->pio_mode;
+ byte recovery_count, recovery_count2, cycle_count;
+ int recovery_time, clock_time;
+
+ if(pio_mode > 5)
+ pio_mode = 5;
+
+ setup_time = ide_pio_timings[pio_mode].setup_time;
+ active_time = ide_pio_timings[pio_mode].active_time;
+
+ recovery_time = cycle_time - (setup_time + active_time);
+ clock_time = 1000 / bus_speed;
+
+ cycle_count = (cycle_time + clock_time - 1) / clock_time;
+ setup_count = (setup_time + clock_time - 1) / clock_time;
+ active_count = (active_time + clock_time - 1) / clock_time;
+
+ if(active_count < 2)
+ active_count = 2;
+
+ recovery_count = (recovery_time + clock_time - 1) / clock_time;
+ recovery_count2 = cycle_count - (setup_count + active_count);
+
+ if(recovery_count2 > recovery_count)
+ recovery_count = recovery_count2;
+ if(recovery_count < 2)
+ recovery_count = 2;
+ if(recovery_count > 17) {
+ active_count += recovery_count - 17;
+ recovery_count = 17;
+ }
+
+ if(active_count > 16)
+ active_count = 16;
+ if(recovery_count > 16)
+ recovery_count = 16;
+
+ printk("active[%d CLKS] recovery[%d CLKS]\n", active_count, recovery_count);
+
+ ns87415_program_modes(drive, active_count, recovery_count);
+}
+
+/* Configure for best PIO mode. */
+static void ns87415_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_pio_data_t d;
+ int bus_speed = ide_system_bus_speed();
+
+ switch(mode_wanted) {
+ case 6:
+ case 7:
+ /* Changes to Fast-devsel are unsupported. */
+ return;
+
+ case 8:
+ case 9:
+ mode_wanted &= 1;
+ /* XXX set_prefetch_mode(index, mode_wanted); */
+ printk("%s: %sbled NS87415 prefetching...\n", drive->name, mode_wanted ? "en" : "dis");
+ return;
+ };
+
+ (void) ide_get_best_pio_mode(drive, mode_wanted, 5, &d);
+
+ printk("%s: selected NS87415 PIO mode%d (%dns)%s ",
+ drive->name, d.pio_mode, d.cycle_time,
+ d.overridden ? " (overriding vendor mode)" : "");
+
+ set_ide_modes(drive, &d, bus_speed);
+}
+#endif /* INCLUDE_OBSOLETE_NS87514_STUFF */
+
+static unsigned int ns87415_count = 0, ns87415_control[MAX_HWIFS] = {0};
+
+/*
+ * This routine either enables/disables (according to drive->present)
+ * the IRQ associated with the port (HWIF(drive)),
+ * and selects either PIO or DMA handshaking for the next I/O operation.
+ */
+static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int bit, new, *old = (unsigned int *) hwif->select_data;
+ unsigned int flags;
+
+ save_flags(flags);
+ cli();
+
+ new = *old;
+
+ /* adjust IRQ enable bit */
+ bit = 1 << (8 + hwif->channel);
+ new = drive->present ? (new | bit) : (new & ~bit);
+
+ /* select PIO or DMA */
+ bit = 1 << (20 + drive->select.b.unit + (hwif->channel << 1));
+ new = use_dma ? (new | bit) : (new & ~bit);
+
+ if (new != *old) {
+ *old = new;
+ (void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, new);
+ }
+ restore_flags(flags);
+}
+
+static void ns87415_selectproc (ide_drive_t *drive)
+{
+ ns87415_prepare_drive (drive, drive->using_dma);
+}
+
+static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+
+ switch (func) {
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
+ {
+ byte dma_stat = inb(hwif->dma_base+2);
+ int rc = (dma_stat & 7) != 4;
+ outb(7, hwif->dma_base); /* from errata: stop DMA, clear INTR & ERROR */
+ outb(dma_stat|6, hwif->dma_base+2); /* clear the INTR & ERROR bits */
+ return rc; /* verify good DMA status */
+ }
+ case ide_dma_write:
+ case ide_dma_read:
+ ns87415_prepare_drive(drive, 1); /* select DMA xfer */
+ if (!ide_dmaproc(func, drive)) /* use standard DMA stuff */
+ return 0;
+ ns87415_prepare_drive(drive, 0); /* DMA failed: select PIO xfer */
+ return 1;
+ default:
+ return ide_dmaproc(func, drive); /* use standard DMA stuff */
+ }
+}
+
+__initfunc(void ide_init_ns87415 (ide_hwif_t *hwif))
+{
+ unsigned int ctrl, progif, using_inta;
+
+ /*
+ * We cannot probe for IRQ: both ports share common IRQ on INTA.
+ * Also, leave IRQ masked during drive probing, to prevent infinite
+ * interrupts from a potentially floating INTA..
+ *
+ * IRQs get unmasked in selectproc when drive is first used.
+ */
+ (void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &ctrl);
+ (void) pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, &progif);
+ /* is irq in "native" mode? */
+ using_inta = progif & (1 << (hwif->channel << 1));
+ if (!using_inta)
+ using_inta = ctrl & (1 << (4 + hwif->channel));
+ (void) pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, 0x40, ctrl);
+ if (hwif->mate) {
+ hwif->select_data = hwif->mate->select_data;
+ } else {
+ hwif->select_data = (unsigned int) &ns87415_control[ns87415_count++];
+ ctrl |= (1 << 8) | (1 << 9); /* mask both IRQs */
+ if (using_inta)
+ ctrl &= ~(1 << 6); /* unmask INTA */
+ *((unsigned int *)hwif->select_data) = ctrl;
+ /*
+ * Set prefetch size to 512 bytes for both ports,
+ * but don't turn on/off prefetching here.
+ */
+ pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, 0x55, 0xee);
+ }
+ if (!using_inta)
+ hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ hwif->irq = hwif->mate->irq; /* share IRQ with mate */
+
+ hwif->dmaproc = &ns87415_dmaproc;
+ hwif->selectproc = &ns87415_selectproc;
+#ifdef INCLUDE_OBSOLETE_NS87514_STUFF
+ hwif->tuneproc = &ns87415_tuneproc;
+#endif /* INCLUDE_OBSOLETE_NS87514_STUFF */
+}
diff --git a/drivers/block/opti621.c b/drivers/block/opti621.c
index 0e0b23758..a4c94b0e6 100644
--- a/drivers/block/opti621.c
+++ b/drivers/block/opti621.c
@@ -110,7 +110,7 @@ int reg_base;
/* there are stored pio numbers from other calls of opti621_tune_drive */
static void compute_pios(ide_drive_t *drive, byte pio)
-/* Store values into drive->timing_data
+/* Store values into drive->drive_data
* second_contr - 0 for primary controller, 1 for secondary
* slave_drive - 0 -> pio is for master, 1 -> pio is for slave
* pio - PIO mode for selected drive (for other we don't know)
@@ -119,17 +119,17 @@ static void compute_pios(ide_drive_t *drive, byte pio)
int d;
ide_hwif_t *hwif = HWIF(drive);
- drive->timing_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+ drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
for (d = 0; d < 2; ++d) {
drive = &hwif->drives[d];
if (drive->present) {
- if (drive->timing_data == PIO_DONT_KNOW)
- drive->timing_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+ if (drive->drive_data == PIO_DONT_KNOW)
+ drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
#ifdef OPTI621_DEBUG
- printk("%s: Selected PIO mode %d\n", drive->name, drive->timing_data);
+ printk("%s: Selected PIO mode %d\n", drive->name, drive->drive_data);
#endif
} else {
- drive->timing_data = PIO_NOT_EXIST;
+ drive->drive_data = PIO_NOT_EXIST;
}
}
}
@@ -192,7 +192,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks)
clks->address_time = cmpt_clk(adr_setup, bus_speed);
clks->data_time = cmpt_clk(data_pls, bus_speed);
clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
- -adr_setup-data_pls, bus_speed);
+ - adr_setup-data_pls, bus_speed);
if (clks->address_time<1) clks->address_time = 1;
if (clks->address_time>4) clks->address_time = 4;
if (clks->data_time<1) clks->data_time = 1;
@@ -220,10 +220,10 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
byte cycle1, cycle2, misc;
ide_hwif_t *hwif = HWIF(drive);
- /* set drive->timing_data for both drives */
+ /* set drive->drive_data for both drives */
compute_pios(drive, pio);
- pio1 = hwif->drives[0].timing_data;
- pio2 = hwif->drives[1].timing_data;
+ pio1 = hwif->drives[0].drive_data;
+ pio2 = hwif->drives[1].drive_data;
compute_clocks(pio1, &first);
compute_clocks(pio2, &second);
@@ -274,11 +274,11 @@ static void opti621_tune_drive (ide_drive_t *drive, byte pio)
}
/*
- * ide_init_opti621() is Called from idedma.c once for each hwif found at boot.
+ * ide_init_opti621() is called once for each hwif found at boot.
*/
-void ide_init_opti621 (byte bus, byte fn, ide_hwif_t *hwif)
+void ide_init_opti621 (ide_hwif_t *hwif)
{
- hwif->drives[0].timing_data = PIO_DONT_KNOW;
- hwif->drives[1].timing_data = PIO_DONT_KNOW;
+ hwif->drives[0].drive_data = PIO_DONT_KNOW;
+ hwif->drives[1].drive_data = PIO_DONT_KNOW;
hwif->tuneproc = &opti621_tune_drive;
}
diff --git a/drivers/block/pdc4030.c b/drivers/block/pdc4030.c
index c161e58b6..30baff570 100644
--- a/drivers/block/pdc4030.c
+++ b/drivers/block/pdc4030.c
@@ -72,9 +72,7 @@ static void promise_selectproc (ide_drive_t *drive)
{
unsigned int number;
- OUT_BYTE(drive->select.all,IDE_SELECT_REG);
- udelay(1); /* paranoia */
- number = ((HWIF(drive)->is_pdc4030_2)<<1) + drive->select.b.unit;
+ number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
OUT_BYTE(number,IDE_FEATURE_REG);
}
@@ -134,7 +132,7 @@ int init_pdc4030 (void)
drive = &hwif->drives[0];
second_hwif = &ide_hwifs[hwif->index+1];
- if(hwif->is_pdc4030_2) /* we've already been found ! */
+ if(hwif->chipset == ide_pdc4030) /* we've already been found ! */
return 1;
if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF)
@@ -172,6 +170,7 @@ int init_pdc4030 (void)
hwif->chipset = second_hwif->chipset = ide_pdc4030;
hwif->mate = second_hwif;
second_hwif->mate = hwif;
+ second_hwif->channel = 1;
hwif->selectproc = second_hwif->selectproc = &promise_selectproc;
/* Shift the remaining interfaces down by one */
for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
@@ -182,7 +181,6 @@ int init_pdc4030 (void)
h->io_ports[IDE_CONTROL_OFFSET] = (h-1)->io_ports[IDE_CONTROL_OFFSET];
h->noprobe = (h-1)->noprobe;
}
- second_hwif->is_pdc4030_2 = 1;
ide_init_hwif_ports(second_hwif->io_ports, hwif->io_ports[IDE_DATA_OFFSET], NULL);
second_hwif->io_ports[IDE_CONTROL_OFFSET] = hwif->io_ports[IDE_CONTROL_OFFSET];
second_hwif->irq = hwif->irq;
diff --git a/drivers/block/qd6580.c b/drivers/block/qd6580.c
index 296aef3a7..9c13bfea9 100644
--- a/drivers/block/qd6580.c
+++ b/drivers/block/qd6580.c
@@ -65,4 +65,5 @@ void init_qd6580 (void)
ide_hwifs[0].tuneproc = &tune_qd6580;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
}
diff --git a/drivers/block/rz1000.c b/drivers/block/rz1000.c
index b7270c559..670fe3e58 100644
--- a/drivers/block/rz1000.c
+++ b/drivers/block/rz1000.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/block/rz1000.c Version 0.03 Mar 20, 1996
+ * linux/drivers/block/rz1000.c Version 0.05 December 8, 1997
*
- * Copyright (C) 1995-1996 Linus Torvalds & author (see below)
+ * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
*/
/*
@@ -9,6 +9,8 @@
*
* This file provides support for disabling the buggy read-ahead
* mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ *
+ * Dunno if this fixes both ports, or only the primary port (?).
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
@@ -26,21 +28,40 @@
#include <linux/pci.h>
#include "ide.h"
-static void init_rz1000 (byte bus, byte fn, const char *name)
+#ifdef CONFIG_BLK_DEV_IDEPCI
+
+__initfunc(void ide_init_rz1000 (ide_hwif_t *hwif)) /* called from ide-pci.c */
+{
+ unsigned short reg;
+
+ hwif->chipset = ide_rz1000;
+ if (!pcibios_read_config_word (hwif->pci_bus, hwif->pci_fn, 0x40, &reg)
+ && !pcibios_write_config_word(hwif->pci_bus, hwif->pci_fn, 0x40, reg & 0xdfff))
+ {
+ printk("%s: disabled chipset read-ahead (buggy RZ1000/RZ1001)\n", hwif->name);
+ } else {
+ hwif->serialized = 1;
+ hwif->drives[0].no_unmask = 1;
+ hwif->drives[1].no_unmask = 1;
+ printk("%s: serialized, disabled unmasking (buggy RZ1000/RZ1001)\n", hwif->name);
+ }
+}
+
+#else
+
+__initfunc(static void init_rz1000 (byte bus, byte fn, const char *name))
{
unsigned short reg, h;
- printk("%s: buggy IDE controller: ", name);
if (!pcibios_read_config_word (bus, fn, PCI_COMMAND, &reg) && !(reg & 1)) {
- printk("disabled (BIOS)\n");
+ printk("%s: buggy IDE controller disabled (BIOS)\n", name);
return;
}
if (!pcibios_read_config_word (bus, fn, 0x40, &reg)
&& !pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))
{
- printk("disabled read-ahead\n");
+ printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
} else {
- printk("\n");
for (h = 0; h < MAX_HWIFS; ++h) {
ide_hwif_t *hwif = &ide_hwifs[h];
if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
@@ -50,13 +71,15 @@ static void init_rz1000 (byte bus, byte fn, const char *name)
hwif->serialized = 1;
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
- printk(" %s: serialized, disabled unmasking\n", hwif->name);
+ if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
+ hwif->channel = 1;
+ printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
}
}
}
}
-void ide_probe_for_rz100x (void)
+__initfunc(void ide_probe_for_rz100x (void)) /* called from ide.c */
{
byte index, bus, fn;
@@ -65,3 +88,5 @@ void ide_probe_for_rz100x (void)
for (index = 0; !pcibios_find_device (PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, index, &bus, &fn); ++index)
init_rz1000 (bus, fn, "RZ1001");
}
+
+#endif CONFIG_BLK_DEV_IDEPCI
diff --git a/drivers/block/trm290.c b/drivers/block/trm290.c
index 7b8fb308c..f88f597d8 100644
--- a/drivers/block/trm290.c
+++ b/drivers/block/trm290.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/block/trm290.c Version 1.00 December 3, 1997
+ * linux/drivers/block/trm290.c Version 1.01 December 5, 1997
*
* Copyright (c) 1997-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
@@ -34,18 +34,20 @@
* The configuration registers are addressed in normal I/O port space
* and are used as follows:
*
- * 0x3df2 when WRITTEN: chiptest register (byte, write-only)
+ * trm290_base depends on jumper settings, and is probed for by ide-dma.c
+ *
+ * trm290_base+2 when WRITTEN: chiptest register (byte, write-only)
* bit7 must always be written as "1"
* bits6-2 undefined
* bit1 1=legacy_compatible_mode, 0=native_pci_mode
* bit0 1=test_mode, 0=normal(default)
*
- * 0x3df2 when READ: status register (byte, read-only)
+ * trm290_base+2 when READ: status register (byte, read-only)
* bits7-2 undefined
* bit1 channel0 busmaster interrupt status 0=none, 1=asserted
* bit0 channel0 interrupt status 0=none, 1=asserted
*
- * 0x3df3 Interrupt mask register
+ * trm290_base+3 Interrupt mask register
* bits7-5 undefined
* bit4 legacy_header: 1=present, 0=absent
* bit3 channel1 busmaster interrupt status 0=none, 1=asserted (read only)
@@ -53,7 +55,7 @@
* bit1 channel1 interrupt mask: 1=masked, 0=unmasked(default)
* bit0 channel0 interrupt mask: 1=masked, 0=unmasked(default)
*
- * 0x3df1 "CPR" Config Pointer Register (byte)
+ * trm290_base+1 "CPR" Config Pointer Register (byte)
* bit7 1=autoincrement CPR bits 2-0 after each access of CDR
* bit6 1=min. 1 wait-state posted write cycle (default), 0=0 wait-state
* bit5 0=enabled master burst access (default), 1=disable (write only)
@@ -61,7 +63,7 @@
* bit3 0=primary IDE channel, 1=secondary IDE channel
* bits2-0 register index for accesses through CDR port
*
- * 0x3df0 "CDR" Config Data Register (word)
+ * trm290_base+0 "CDR" Config Data Register (word)
* two sets of seven config registers,
* selected by CPR bit 3 (channel) and CPR bits 2-0 (index 0 to 6),
* each index defined below:
@@ -130,98 +132,137 @@
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/hdreg.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+
#include <asm/io.h>
#include "ide.h"
-static void select_dma_or_pio(ide_hwif_t *hwif, int dma)
+static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
{
- static int previous[2] = {-1,-1};
+ ide_hwif_t *hwif = HWIF(drive);
+ unsigned int reg;
unsigned long flags;
- if (previous[hwif->pci_port] != dma) {
- unsigned short cfg1 = dma ? 0xa3 : 0x21;
- previous[hwif->pci_port] = dma;
- save_flags(flags);
- cli();
- outb(0x51|(hwif->pci_port<<3),0x3df1);
- outw(cfg1,0x3df0);
- restore_flags(flags);
+ /* select PIO or DMA */
+ reg = use_dma ? (0x21 | 0x82) : (0x21 & ~0x82);
+
+ save_flags(flags);
+ cli();
+
+ if (reg != hwif->select_data) {
+ hwif->select_data = reg;
+ outb(0x51|(hwif->channel<<3), hwif->config_data+1); /* set PIO/DMA */
+ outw(reg & 0xff, hwif->config_data);
+ }
+
+ /* enable IRQ if not probing */
+ if (drive->present) {
+ reg = inw(hwif->config_data+3) & 0x13;
+ reg &= ~(1 << hwif->channel);
+ outw(reg, hwif->config_data+3);
}
+
+ restore_flags(flags);
}
-/*
- * trm290_dma_intr() is the handler for trm290 disk read/write DMA interrupts
- */
-static void trm290_dma_intr (ide_drive_t *drive)
+static void trm290_selectproc (ide_drive_t *drive)
{
- byte stat;
- int i;
- struct request *rq = HWGROUP(drive)->rq;
-
- stat = GET_STAT(); /* get drive status */
- if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
- unsigned short dma_stat = inw(HWIF(drive)->dma_base + 2);
- if (dma_stat == 0x00ff) {
- rq = HWGROUP(drive)->rq;
- for (i = rq->nr_sectors; i > 0;) {
- i -= rq->current_nr_sectors;
- ide_end_request(1, HWGROUP(drive));
- }
- return;
- }
- printk("%s: bad trm290 DMA status: 0x%04x\n", drive->name, dma_stat);
- }
- sti();
- ide_error(drive, "dma_intr", stat);
+ trm290_prepare_drive(drive, drive->using_dma);
}
static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned int count, reading = 1 << 1;
+ unsigned int count, reading = 2, writing = 0;
- if (drive->media == ide_disk) {
- switch (func) {
- case ide_dma_write:
- reading = 0;
+ switch (func) {
+ case ide_dma_write:
+ reading = 0;
+ writing = 1;
#ifdef TRM290_NO_DMA_WRITES
- break; /* always use PIO for writes */
+ break; /* always use PIO for writes */
#endif
- case ide_dma_read:
- if (!(count = ide_build_dmatable(drive)))
- break; /* try PIO instead of DMA */
- select_dma_or_pio(hwif, 1); /* select DMA mode */
- outl_p(virt_to_bus(hwif->dmatable)|reading, hwif->dma_base);
- outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
- ide_set_handler(drive, &trm290_dma_intr, WAIT_CMD);
- OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ case ide_dma_read:
+ if (!(count = ide_build_dmatable(drive)))
+ break; /* try PIO instead of DMA */
+ trm290_prepare_drive(drive, 1); /* select DMA xfer */
+ outl(virt_to_bus(hwif->dmatable)|reading|writing, hwif->dma_base);
+ outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
+ if (drive->media != ide_disk)
return 0;
- default:
- return ide_dmaproc(func, drive);
- }
+ ide_set_handler(drive, &ide_dma_intr, WAIT_CMD);
+ OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
+ case ide_dma_begin:
+ return 0;
+ case ide_dma_end:
+ return (inw(hwif->dma_base+2) != 0x00ff);
+ default:
+ return ide_dmaproc(func, drive);
}
- select_dma_or_pio(hwif, 0); /* force PIO mode for this operation */
+ trm290_prepare_drive(drive, 0); /* select PIO xfer */
return 1;
}
-static void trm290_selectproc (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
-
- select_dma_or_pio(hwif, drive->using_dma);
- OUT_BYTE(drive->select.all, hwif->io_ports[IDE_SELECT_OFFSET]);
-}
-
/*
* Invoked from ide-dma.c at boot time.
*/
-__initfunc(void ide_init_trm290 (byte bus, byte fn, ide_hwif_t *hwif))
+__initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
{
+ unsigned int cfgbase = 0;
+ unsigned long flags;
+ byte reg, progif;
+
hwif->chipset = ide_trm290;
- hwif->selectproc = trm290_selectproc;
- hwif->drives[0].autotune = 2; /* play it safe */
- hwif->drives[1].autotune = 2; /* play it safe */
- ide_setup_dma(hwif, hwif->pci_port ? 0x3d74 : 0x3df4, 2);
+ if (!pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, 0x09, &progif) && (progif & 5)
+ && !pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x20, &cfgbase) && cfgbase)
+ {
+ hwif->config_data = cfgbase & ~1;
+ printk("TRM290: chip config base at 0x%04x\n", hwif->config_data);
+ } else {
+ hwif->config_data = 0x3df4;
+ printk("TRM290: using default config base at 0x%04x\n", hwif->config_data);
+ }
+
+ save_flags(flags);
+ cli();
+ /* put config reg into first byte of hwif->select_data */
+ outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+ hwif->select_data = 0x21; /* select PIO as default */
+ outb(hwif->select_data, hwif->config_data);
+ reg = inb(hwif->config_data+3); /* get IRQ info */
+ reg = (reg & 0x10) | 0x03; /* mask IRQs for both ports */
+ outb(reg, hwif->config_data+3);
+ restore_flags(flags);
+
+ if ((reg & 0x10))
+ hwif->irq = hwif->channel ? 15 : 14; /* legacy mode */
+ else if (!hwif->irq && hwif->mate && hwif->mate->irq)
+ hwif->irq = hwif->mate->irq; /* sharing IRQ with mate */
+ ide_setup_dma(hwif, (hwif->channel ? hwif->config_data ^ 0x0080 : hwif->config_data) + 4, 2);
hwif->dmaproc = &trm290_dmaproc;
+ hwif->selectproc = &trm290_selectproc;
+ hwif->no_autodma = 1; /* play it safe for now */
+#if 1
+ {
+ /*
+ * My trm290-based card doesn't seem to work with all possible values
+ * for the control basereg, so this kludge ensures that we use only
+ * values that are known to work. Ugh. -ml
+ */
+ unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+ static unsigned short next_offset = 0;
+
+ outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+ old = inw(hwif->config_data) & ~1;
+ if (old != compat && inb(old+2) == 0xff) {
+ compat += (next_offset += 0x400); /* leave lower 10 bits untouched */
+ hwif->io_ports[IDE_CONTROL_OFFSET] = compat + 2; /* FIXME: should do a check_region */
+ outw(compat|1, hwif->config_data);
+ printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
+ }
+ }
+#endif
}
diff --git a/drivers/block/umc8672.c b/drivers/block/umc8672.c
index 628e13bb5..8856dad35 100644
--- a/drivers/block/umc8672.c
+++ b/drivers/block/umc8672.c
@@ -153,4 +153,5 @@ void init_umc8672 (void) /* called from ide.c */
ide_hwifs[1].tuneproc = &tune_umc;
ide_hwifs[0].mate = &ide_hwifs[1];
ide_hwifs[1].mate = &ide_hwifs[0];
+ ide_hwifs[1].channel = 1;
}